módulo Python para converter PDF em texto

votos
341

Quais são os melhores módulos Python para converter arquivos PDF em texto?

Publicado 25/08/2008 em 05:44
fonte usuário
Em outras línguas...                            


13 respostas

votos
130

O PDFMiner pacote mudou desde codeape postou.

EDIT (novamente):

PDFMiner foi atualizado novamente na versão 20100213

Você pode verificar a versão que você instalou com o seguinte:

>>> import pdfminer
>>> pdfminer.__version__
'20100213'

Aqui está a versão atualizada (com comentários sobre o que eu mudei / agregado):

def pdf_to_csv(filename):
    from cStringIO import StringIO  #<-- added so you can copy/paste this to try it
    from pdfminer.converter import LTTextItem, TextConverter
    from pdfminer.pdfparser import PDFDocument, PDFParser
    from pdfminer.pdfinterp import PDFResourceManager, PDFPageInterpreter

    class CsvConverter(TextConverter):
        def __init__(self, *args, **kwargs):
            TextConverter.__init__(self, *args, **kwargs)

        def end_page(self, i):
            from collections import defaultdict
            lines = defaultdict(lambda : {})
            for child in self.cur_item.objs:
                if isinstance(child, LTTextItem):
                    (_,_,x,y) = child.bbox                   #<-- changed
                    line = lines[int(-y)]
                    line[x] = child.text.encode(self.codec)  #<-- changed

            for y in sorted(lines.keys()):
                line = lines[y]
                self.outfp.write(";".join(line[x] for x in sorted(line.keys())))
                self.outfp.write("\n")

    # ... the following part of the code is a remix of the 
    # convert() function in the pdfminer/tools/pdf2text module
    rsrc = PDFResourceManager()
    outfp = StringIO()
    device = CsvConverter(rsrc, outfp, codec="utf-8")  #<-- changed 
        # becuase my test documents are utf-8 (note: utf-8 is the default codec)

    doc = PDFDocument()
    fp = open(filename, 'rb')
    parser = PDFParser(fp)       #<-- changed
    parser.set_document(doc)     #<-- added
    doc.set_parser(parser)       #<-- added
    doc.initialize('')

    interpreter = PDFPageInterpreter(rsrc, device)

    for i, page in enumerate(doc.get_pages()):
        outfp.write("START PAGE %d\n" % i)
        interpreter.process_page(page)
        outfp.write("END PAGE %d\n" % i)

    device.close()
    fp.close()

    return outfp.getvalue()

Edit (mais uma vez):

Aqui está uma atualização para a versão mais recente em pypi , 20100619p1. Em suma, eu substituído LTTextItemcom LTChare passou uma instância de LAParams para o construtor CsvConverter.

def pdf_to_csv(filename):
    from cStringIO import StringIO  
    from pdfminer.converter import LTChar, TextConverter    #<-- changed
    from pdfminer.layout import LAParams
    from pdfminer.pdfparser import PDFDocument, PDFParser
    from pdfminer.pdfinterp import PDFResourceManager, PDFPageInterpreter

    class CsvConverter(TextConverter):
        def __init__(self, *args, **kwargs):
            TextConverter.__init__(self, *args, **kwargs)

        def end_page(self, i):
            from collections import defaultdict
            lines = defaultdict(lambda : {})
            for child in self.cur_item.objs:
                if isinstance(child, LTChar):               #<-- changed
                    (_,_,x,y) = child.bbox                   
                    line = lines[int(-y)]
                    line[x] = child.text.encode(self.codec)

            for y in sorted(lines.keys()):
                line = lines[y]
                self.outfp.write(";".join(line[x] for x in sorted(line.keys())))
                self.outfp.write("\n")

    # ... the following part of the code is a remix of the 
    # convert() function in the pdfminer/tools/pdf2text module
    rsrc = PDFResourceManager()
    outfp = StringIO()
    device = CsvConverter(rsrc, outfp, codec="utf-8", laparams=LAParams())  #<-- changed
        # becuase my test documents are utf-8 (note: utf-8 is the default codec)

    doc = PDFDocument()
    fp = open(filename, 'rb')
    parser = PDFParser(fp)       
    parser.set_document(doc)     
    doc.set_parser(parser)       
    doc.initialize('')

    interpreter = PDFPageInterpreter(rsrc, device)

    for i, page in enumerate(doc.get_pages()):
        outfp.write("START PAGE %d\n" % i)
        if page is not None:
            interpreter.process_page(page)
        outfp.write("END PAGE %d\n" % i)

    device.close()
    fp.close()

    return outfp.getvalue()

EDIT (mais uma vez):

Atualizado para a versão 20110515(graças a Oeufcoque Penteano!):

def pdf_to_csv(filename):
    from cStringIO import StringIO  
    from pdfminer.converter import LTChar, TextConverter
    from pdfminer.layout import LAParams
    from pdfminer.pdfparser import PDFDocument, PDFParser
    from pdfminer.pdfinterp import PDFResourceManager, PDFPageInterpreter

    class CsvConverter(TextConverter):
        def __init__(self, *args, **kwargs):
            TextConverter.__init__(self, *args, **kwargs)

        def end_page(self, i):
            from collections import defaultdict
            lines = defaultdict(lambda : {})
            for child in self.cur_item._objs:                #<-- changed
                if isinstance(child, LTChar):
                    (_,_,x,y) = child.bbox                   
                    line = lines[int(-y)]
                    line[x] = child._text.encode(self.codec) #<-- changed

            for y in sorted(lines.keys()):
                line = lines[y]
                self.outfp.write(";".join(line[x] for x in sorted(line.keys())))
                self.outfp.write("\n")

    # ... the following part of the code is a remix of the 
    # convert() function in the pdfminer/tools/pdf2text module
    rsrc = PDFResourceManager()
    outfp = StringIO()
    device = CsvConverter(rsrc, outfp, codec="utf-8", laparams=LAParams())
        # becuase my test documents are utf-8 (note: utf-8 is the default codec)

    doc = PDFDocument()
    fp = open(filename, 'rb')
    parser = PDFParser(fp)       
    parser.set_document(doc)     
    doc.set_parser(parser)       
    doc.initialize('')

    interpreter = PDFPageInterpreter(rsrc, device)

    for i, page in enumerate(doc.get_pages()):
        outfp.write("START PAGE %d\n" % i)
        if page is not None:
            interpreter.process_page(page)
        outfp.write("END PAGE %d\n" % i)

    device.close()
    fp.close()

    return outfp.getvalue()
Respondeu 10/08/2009 em 21:47
fonte usuário

votos
116

Tente PDFMiner. Ele pode extrair texto de arquivos PDF como HTML, SGML ou formato de "Tagged PDF".

http://www.unixuser.org/~euske/python/pdfminer/index.html

O formato PDF Tagged parece ser o mais limpo, e que eliminasse as tags XML deixa apenas o texto nu.

A Python 3 versão está disponível em:

Respondeu 25/08/2008 em 06:21
fonte usuário

votos
49

Uma vez que nenhum para estas soluções suportam a versão mais recente de PDFMiner Eu escrevi uma solução simples que irá retornar o texto de um PDF usando PDFMiner. Isto irá funcionar para aqueles que estão recebendo erros de importação comprocess_pdf

import sys
from pdfminer.pdfinterp import PDFResourceManager, PDFPageInterpreter
from pdfminer.pdfpage import PDFPage
from pdfminer.converter import XMLConverter, HTMLConverter, TextConverter
from pdfminer.layout import LAParams
from cStringIO import StringIO

def pdfparser(data):

    fp = file(data, 'rb')
    rsrcmgr = PDFResourceManager()
    retstr = StringIO()
    codec = 'utf-8'
    laparams = LAParams()
    device = TextConverter(rsrcmgr, retstr, codec=codec, laparams=laparams)
    # Create a PDF interpreter object.
    interpreter = PDFPageInterpreter(rsrcmgr, device)
    # Process each page contained in the document.

    for page in PDFPage.get_pages(fp):
        interpreter.process_page(page)
        data =  retstr.getvalue()

    print data

if __name__ == '__main__':
    pdfparser(sys.argv[1])  

Veja abaixo o código que funciona para Python 3:

import sys
from pdfminer.pdfinterp import PDFResourceManager, PDFPageInterpreter
from pdfminer.pdfpage import PDFPage
from pdfminer.converter import XMLConverter, HTMLConverter, TextConverter
from pdfminer.layout import LAParams
import io

def pdfparser(data):

    fp = open(data, 'rb')
    rsrcmgr = PDFResourceManager()
    retstr = io.StringIO()
    codec = 'utf-8'
    laparams = LAParams()
    device = TextConverter(rsrcmgr, retstr, codec=codec, laparams=laparams)
    # Create a PDF interpreter object.
    interpreter = PDFPageInterpreter(rsrcmgr, device)
    # Process each page contained in the document.

    for page in PDFPage.get_pages(fp):
        interpreter.process_page(page)
        data =  retstr.getvalue()

    print(data)

if __name__ == '__main__':
    pdfparser(sys.argv[1])  
Respondeu 04/02/2014 em 23:16
fonte usuário

votos
42

pyPdf funciona bem (assumindo que você está trabalhando com PDFs bem formado). Se tudo que você quer é o texto (com espaços), você só pode fazer:

import pyPdf
pdf = pyPdf.PdfFileReader(open(filename, "rb"))
for page in pdf.pages:
    print page.extractText()

Você também pode facilmente ter acesso aos metadados, dados de imagem, e assim por diante.

Um comentário nas notas de código extractText:

Localizar todos os comandos de desenho de texto, na ordem em que são fornecidos no fluxo de conteúdo, e extrair o texto. Isso funciona bem para alguns arquivos PDF, mas mal para os outros, dependendo do gerador utilizado. Este será refinado no futuro. Não confie na ordem de texto que sai desta função, uma vez que irá mudar se esta função se torna mais sofisticado.

Seja ou não este é um problema depende do que você está fazendo com o texto (por exemplo, se a ordem não importa, está tudo bem, ou se o gerador adiciona texto para o fluxo na ordem em que serão exibidos, está tudo bem) . Eu tenho o código de extração pyPdf no uso diário, sem quaisquer problemas.

Respondeu 07/09/2008 em 05:47
fonte usuário

votos
39

Pdftotext Um programa de código aberto (parte do Xpdf) que você poderia chamar de python (não o que você pediu, mas pode ser útil). Eu usei-o sem problemas. Acho que o Google usá-lo no google desktop.

Respondeu 28/08/2008 em 10:46
fonte usuário

votos
21

Você também pode facilmente usar pdfminer como uma biblioteca. Você tem acesso ao modelo de conteúdo do pdf, e pode criar sua própria extração de texto. Fiz isso para converter o conteúdo de pdf para texto e vírgula separados, utilizando o código abaixo.

A função simplesmente ordena os objetos de conteúdo itemdetexto de acordo com sua y e x coordenadas, e produz itens com a mesma coordenada y como uma linha de texto, separando os objetos na mesma linha com ';' personagens.

Usando essa abordagem, eu era capaz de extrair o texto de um PDF que nenhuma outra ferramenta foi capaz de extrair o conteúdo adequado para posterior análise de. Outras ferramentas que eu tentei incluir pdftotext, ps2ascii eo pdftextonline.com ferramenta online.

pdfminer é uma ferramenta de valor inestimável para pdf-raspagem.


def pdf_to_csv(filename):
    from pdflib.page import TextItem, TextConverter
    from pdflib.pdfparser import PDFDocument, PDFParser
    from pdflib.pdfinterp import PDFResourceManager, PDFPageInterpreter

    class CsvConverter(TextConverter):
        def __init__(self, *args, **kwargs):
            TextConverter.__init__(self, *args, **kwargs)

        def end_page(self, i):
            from collections import defaultdict
            lines = defaultdict(lambda : {})
            for child in self.cur_item.objs:
                if isinstance(child, TextItem):
                    (_,_,x,y) = child.bbox
                    line = lines[int(-y)]
                    line[x] = child.text

            for y in sorted(lines.keys()):
                line = lines[y]
                self.outfp.write(";".join(line[x] for x in sorted(line.keys())))
                self.outfp.write("\n")

    # ... the following part of the code is a remix of the 
    # convert() function in the pdfminer/tools/pdf2text module
    rsrc = PDFResourceManager()
    outfp = StringIO()
    device = CsvConverter(rsrc, outfp, "ascii")

    doc = PDFDocument()
    fp = open(filename, 'rb')
    parser = PDFParser(doc, fp)
    doc.initialize('')

    interpreter = PDFPageInterpreter(rsrc, device)

    for i, page in enumerate(doc.get_pages()):
        outfp.write("START PAGE %d\n" % i)
        interpreter.process_page(page)
        outfp.write("END PAGE %d\n" % i)

    device.close()
    fp.close()

    return outfp.getvalue()

ATUALIZAÇÃO :

O código acima é escrito contra uma versão antiga da API, consulte o meu comentário abaixo.

Respondeu 24/11/2008 em 15:20
fonte usuário

votos
16

slate é um projeto que faz com que seja muito simples de usar PDFMiner de uma biblioteca:

>>> with open('example.pdf') as f:
...    doc = slate.PDF(f)
...
>>> doc
[..., ..., ...]
>>> doc[1]
'Text from page 2...'   
Respondeu 31/01/2011 em 01:27
fonte usuário

votos
8

I necessário para converter um PDF específico para texto simples dentro de um módulo python. Eu costumava PDFMiner 20110515, depois de ler através de seu pdf2txt.py ferramenta que eu escrevi este trecho simples:

from cStringIO import StringIO
from pdfminer.pdfinterp import PDFResourceManager, process_pdf
from pdfminer.converter import TextConverter
from pdfminer.layout import LAParams

def to_txt(pdf_path):
    input_ = file(pdf_path, 'rb')
    output = StringIO()

    manager = PDFResourceManager()
    converter = TextConverter(manager, output, laparams=LAParams())
    process_pdf(manager, converter, input_)

    return output.getvalue() 
Respondeu 28/05/2013 em 17:01
fonte usuário

votos
5

Repurposing o código pdf2txt.py que vem com pdfminer; você pode fazer uma função que irá tomar um caminho para o pdf; opcionalmente, um outtype (txt | html | xml | tag) e opta como o PDF2TXT comando { '-o': '/path/to/outfile.txt' ...}. Por padrão, você pode ligar no:

convert_pdf(path)

Um arquivo de texto será criado, um irmão no sistema de arquivos para o PDF original.

def convert_pdf(path, outtype='txt', opts={}):
    import sys
    from pdfminer.pdfinterp import PDFResourceManager, PDFPageInterpreter, process_pdf
    from pdfminer.converter import XMLConverter, HTMLConverter, TextConverter, TagExtractor
    from pdfminer.layout import LAParams
    from pdfminer.pdfparser import PDFDocument, PDFParser
    from pdfminer.pdfdevice import PDFDevice
    from pdfminer.cmapdb import CMapDB

    outfile = path[:-3] + outtype
    outdir = '/'.join(path.split('/')[:-1])

    debug = 0
    # input option
    password = ''
    pagenos = set()
    maxpages = 0
    # output option
    codec = 'utf-8'
    pageno = 1
    scale = 1
    showpageno = True
    laparams = LAParams()
    for (k, v) in opts:
        if k == '-d': debug += 1
        elif k == '-p': pagenos.update( int(x)-1 for x in v.split(',') )
        elif k == '-m': maxpages = int(v)
        elif k == '-P': password = v
        elif k == '-o': outfile = v
        elif k == '-n': laparams = None
        elif k == '-A': laparams.all_texts = True
        elif k == '-D': laparams.writing_mode = v
        elif k == '-M': laparams.char_margin = float(v)
        elif k == '-L': laparams.line_margin = float(v)
        elif k == '-W': laparams.word_margin = float(v)
        elif k == '-O': outdir = v
        elif k == '-t': outtype = v
        elif k == '-c': codec = v
        elif k == '-s': scale = float(v)
    #
    CMapDB.debug = debug
    PDFResourceManager.debug = debug
    PDFDocument.debug = debug
    PDFParser.debug = debug
    PDFPageInterpreter.debug = debug
    PDFDevice.debug = debug
    #
    rsrcmgr = PDFResourceManager()
    if not outtype:
        outtype = 'txt'
        if outfile:
            if outfile.endswith('.htm') or outfile.endswith('.html'):
                outtype = 'html'
            elif outfile.endswith('.xml'):
                outtype = 'xml'
            elif outfile.endswith('.tag'):
                outtype = 'tag'
    if outfile:
        outfp = file(outfile, 'w')
    else:
        outfp = sys.stdout
    if outtype == 'txt':
        device = TextConverter(rsrcmgr, outfp, codec=codec, laparams=laparams)
    elif outtype == 'xml':
        device = XMLConverter(rsrcmgr, outfp, codec=codec, laparams=laparams, outdir=outdir)
    elif outtype == 'html':
        device = HTMLConverter(rsrcmgr, outfp, codec=codec, scale=scale, laparams=laparams, outdir=outdir)
    elif outtype == 'tag':
        device = TagExtractor(rsrcmgr, outfp, codec=codec)
    else:
        return usage()

    fp = file(path, 'rb')
    process_pdf(rsrcmgr, device, fp, pagenos, maxpages=maxpages, password=password)
    fp.close()
    device.close()

    outfp.close()
    return
Respondeu 18/07/2010 em 20:17
fonte usuário

votos
1

Eu tenho usado pdftohtml com o argumento '-xml', leia o resultado com subprocess.Popen (), que lhe dará x coord, y coord, largura, altura e tipo de letra, de cada 'trecho' de texto no pdf. Eu acho que isso é o que evince "provavelmente usa também porque as mesmas mensagens de erro vomitar.

Se você precisa para processar dados colunar, ele fica um pouco mais complicado, pois você tem que inventar um algoritmo que se adapta ao seu arquivo pdf. O problema é que os programas que fazem arquivos PDF realmente não necessariamente colocar para fora o texto em qualquer formato lógico. Você pode tentar algoritmos de ordenação simples e funciona às vezes, mas não pode haver pequenos 'retardatários' e 'estáticas', pedaços de texto que não se colocam na ordem que você pensava que seria ... então você tem que ser criativo.

Levei cerca de 5 horas para descobrir um para o PDF do que eu estava trabalhando. Mas ele funciona muito bem agora. Boa sorte.

Respondeu 12/11/2010 em 23:34
fonte usuário

votos
1

Além disso, há PDFTextStream que é uma biblioteca Java comercial que também pode ser usado a partir de Python.

Respondeu 12/11/2008 em 18:08
fonte usuário

votos
0

Encontrado que a solução de hoje. Funciona muito bem para mim. Mesmo renderização de páginas PDF para imagens PNG. http://www.swftools.org/gfx_tutorial.html

Respondeu 31/01/2011 em 01:22
fonte usuário

votos
0

PDFminer me deu talvez uma linha [página 1 de 7 ...] em todas as páginas de um arquivo pdf Tentei com ele.

A melhor resposta que eu tenho até agora é pdftoipe, ou o código c ++ é baseado em Xpdf.

veja a minha pergunta para o que a saída do pdftoipe parece.

Respondeu 26/08/2008 em 03:04
fonte usuário

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more