Сведения о вопросе

Getthesound

22:24, 12th August, 2020

Теги

Python модуль для преобразования PDF в текст

Просмотров: 544   Ответов: 13

Какие модули Python лучше всего подходят для преобразования PDF файлов в текст?



  Сведения об ответе

VERSUION

14:46, 3rd August, 2020

Пакет PDFMiner изменился с момента публикации codeape.

EDIT (опять же):

PDFMiner был обновлен снова в версии 20100213

Вы можете проверить установленную версию следующим образом:

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

Вот обновленная версия (с комментариями о том, что я changed/added):

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 (еще раз):

Вот обновление для последней версии в pypi, 20100619p1 . Короче говоря, Я заменил LTTextItem на LTChar и передал экземпляр LAParams конструктору 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 (еще раз):

Обновлено для версии 20110515 (благодаря 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()


  Сведения об ответе

PROGA

11:17, 17th August, 2020

Попробуйте PDFMiner . Он может извлекать текст из PDF файлов в формате HTML, SGML или "Tagged PDF".

Формат с тегами PDF кажется самым чистым, и удаление тегов XML оставляет только голый текст.

Версия Python 3 доступна под:


  Сведения об ответе

Chhiki

16:27, 5th August, 2020

Поскольку ни одно из этих решений не поддерживает последнюю версию PDFMiner, я написал простое решение, которое вернет текст pdf, используя PDFMiner. Это будет работать для тех, кто получает ошибки импорта с process_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])  

Смотрите ниже код, который работает для 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])  


  Сведения об ответе

PHPH

03:13, 20th August, 2020

Pdftotext -программа с открытым исходным кодом (часть Xpdf), которую можно вызвать из python (не то, что вы просили, но может быть полезно). Я использовал его без проблем. Я думаю, что google использует его в Google desktop.


  Сведения об ответе

LAST

09:36, 22nd August, 2020

pyPDF работает нормально (при условии, что вы работаете с хорошо сформированным PDFs). Если все, что вы хотите, это текст (с пробелами), вы можете просто сделать:

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

Вы также можете легко получить доступ к метаданным, данным изображений и так далее.

Комментарий в примечаниях к коду extractText:

Найдите все команды рисования текста, в порядок их предоставления в поток содержимого и извлечение текста. Это хорошо работает для некоторых файлов PDF, но плохо для других, в зависимости от используемый генератор. Это будет утонченный в будущем. Не полагайтесь на порядок текста, выходящего из этого функция, как она изменится, если это функция сделана более изощренной.

Является ли это проблемой или нет, зависит от того, что вы делаете с текстом (например, если порядок не имеет значения, это нормально, или если генератор добавляет текст в поток в том порядке, в котором он будет отображаться, это нормально). У меня есть код извлечения pyPdf в ежедневном использовании, без каких-либо проблем.


  Сведения об ответе

qwerty101

22:57, 18th August, 2020

Вы также можете довольно легко использовать pdfminer в качестве библиотеки. У вас есть доступ к модели содержимого pdf и вы можете создавать свои собственные извлечения текста. Я сделал это, чтобы преобразовать содержимое pdf в разделенный точкой с запятой текст, используя приведенный ниже код.

Функция просто сортирует объекты содержимого TextItem в соответствии с их координатами y и x и выводит элементы с той же координатой y в виде одной строки текста, разделяя объекты на той же строке символами';'.

Используя этот подход, я смог извлечь текст из pdf, из которого ни один другой инструмент не смог извлечь содержимое, пригодное для дальнейшего анализа. Другие инструменты, которые я пробовал, включают pdftotext, ps2ascii и онлайн-инструмент pdftextonline.com.

pdfminer-это бесценный инструмент для pdf-выскабливания.


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()

UPDATE :

Приведенный выше код написан против старой версии API, см. Мой комментарий ниже.


  Сведения об ответе

VERSUION

03:54, 10th August, 2020

slate -это проект, который делает его очень простым в использовании PDFMiner из библиотеки:

>>> with open('example.pdf') as f:
...    doc = slate.PDF(f)
...
>>> doc
[..., ..., ...]
>>> doc[1]
'Text from page 2...'   


  Сведения об ответе

9090

12:02, 27th August, 2020

Мне нужно было преобразовать определенный PDF в обычный текст в модуле python. Я использовал PDFMiner 20110515, после прочтения их инструмента pdf2txt.py я написал этот простой фрагмент:

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() 


  Сведения об ответе

LIZA

21:18, 3rd August, 2020

Перепрофилирование кода pdf2txt.py, который поставляется с pdfminer; вы можете создать функцию, которая будет принимать путь к pdf; необязательно, outtype (txt|html|xml|tag) и выбирается как командная строка pdf2txt {'- o': '/path/to/outfile.txt' ...}. По умолчанию вы можете позвонить:

convert_pdf(path)

Будет создан текстовый файл, родственный в файловой системе оригиналу pdf.

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


  Сведения об ответе

screen

21:06, 1st October, 2020

Я использовал pdftohtml с аргументом -xml , прочитал результат с помощью subprocess.Popen(), который даст вам x coord, y coord, ширину, высоту и шрифт каждого фрагмента текста в pdf. Я думаю, что это то, что 'evince', вероятно, тоже использует, потому что те же сообщения об ошибках извергаются.

Если вам нужно обработать столбчатые данные, это становится немного сложнее, так как вам нужно придумать алгоритм, соответствующий вашему файлу pdf. Проблема в том, что программы, которые создают файлы PDF, на самом деле не обязательно выкладывают текст в любом логическом формате. Вы можете попробовать простые алгоритмы сортировки, и это иногда работает, но может быть немного 'stragglers' и 'strays', фрагментов текста, которые не помещаются в том порядке, в котором вы думали, что они будут. Так что вам придется проявить творческий подход.

Мне потребовалось около 5 часов, чтобы найти один для pdf, над которым я работал. Но сейчас это работает довольно хорошо. Удачи.


  Сведения об ответе

ASER

10:48, 21st August, 2020

PDFminer дал мне, пожалуй, одну строчку [Страница 1 из 7...] на каждой странице файла pdf я пытался использовать его.

Лучший ответ, который у меня есть до сих пор, - это pdftoipe, или код c++, основанный на Xpdf.

смотрите мой вопрос о том, как выглядит вывод pdftoipe.


  Сведения об ответе

ASSembler

02:34, 4th August, 2020

Кроме того, есть PDFTextStream , который является коммерческой библиотекой Java, которая также может быть использована из Python.


  Сведения об ответе

piter

11:40, 27th August, 2020

Сегодня я нашел это решение. Отлично работает для меня. Даже рендеринг PDF страниц в PNG изображений. http://www.swftools.org/gfx_tutorial.html


Ответить на вопрос

Чтобы ответить на вопрос вам нужно войти в систему или зарегистрироваться