2008-08-25 4 views

ответ

108

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

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

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

Python, 3 версия доступна в разделе:

+1

Я просто добавил ответ, описывающий использование pdfminer в качестве библиотеки. – codeape 2008-11-24 14:21:13

0

PDFminer дал мне, возможно, одну строку [страница 1 из 7 ...] на каждой странице PDF-файла, который я попытался с Это.

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

см. my question, для чего выглядит выход pdftoipe.

38

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

+5

Это, пожалуй, самый полезный из перечисленных здесь инструментов, с опцией `-layout` для сохранения текста в том же положении, что и в PDF-файле. Теперь, если бы я мог понять, как передать содержимое PDF в него. – 2012-05-31 06:00:51

42

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

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

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

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

Locate all text drawing commands, in the order they are provided in the content stream, and extract the text. This works well for some PDF files, but poorly for others, depending on the generator used. This will be refined in the future. Do not rely on the order of text coming out of this function, as it will change if this function is made more sophisticated.

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

+6

поддержка unicode :( – PanosJee 2010-10-14 10:30:56

1

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

21

Вы также можете легко использовать 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 см мой комментарий ниже.

+0

Какие плагины вам нужны для этого? Я загрузил и установил pdfminer, но этого недостаточно ... – kxk 2011-07-24 17:38:08

+1

Вышеприведенный код написан на старой версии PDFminer. API изменился в более поздних версиях (например, теперь пакет `` pdfminer``, а не `` pdflib``). Я предлагаю вам взглянуть на источник `` pdf2txt.py`` в источнике PDFminer, код выше был вдохновлен старой версией этого файла. – codeape 2011-07-25 06:04:14

128

PDFMiner пакет изменился с codeape.

EDIT (опять же):

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

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

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

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

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

Отлично, спасибо за обновление с информацией о новой версии. – codeape 2009-08-21 19:58:32

+0

+1, tgray, отличный образец кода! – Mark 2010-02-22 15:23:24

+0

В работе [6]: импорт pdfminer В работе [7]: pdfminer .__ version__ Out [7]: '20100424' В работе [8]: от pdfminer.converter импорта LTTextItem ImportError: не может импортировать имя LTTextItem .... LITERALS_DCT_DECODE LTChar LTImage LTPolygon LTTextBox LITERAL_DEVICE_GRAY LTContainer LTLine LTRect LTTextGroup LITERAL_DEVICE_RGB LTFigure LTPage LTText LTTextLine – 2010-07-17 22:41:09

5

Repurposing код 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 
1

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

Если вам нужно обработать столбчатые данные, он становится немного сложнее, поскольку вам нужно придумать алгоритм, который подходит вашему файлу PDF. Проблема в том, что программы, которые делают PDF-файлы, на самом деле не обязательно выкладывают текст в любом логическом формате. Вы можете попробовать простые алгоритмы сортировки, и это работает иногда, но могут быть небольшие «отставшие» и «страйки», фрагменты текста, которые не попадают в порядок, который, по вашему мнению, они ... так что вам нужно проявить творческий подход.

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

16

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

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

мне нужно преобразовать конкретный PDF в виде обычного текста в модуле питона. Я использовал 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() 
48

Поскольку ни для этих решений не поддерживает последнюю версию 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]) 
Смежные вопросы