Извлечение текста из файла PDF с использованием PDFMiner в Python?

Python версия 2.7

Я ищу документацию или примеры того, как извлечь текст из файла PDF, используя PDFMiner с Python.

Похоже, что PDFMiner обновил свой API, и все соответствующие примеры, которые я нашел, содержат устаревший код (классы и методы изменились). В библиотеках, которые я нашел, которые облегчают задачу извлечения текста из файла PDF, используется старый синтаксис PDFMiner, поэтому я не уверен, как это сделать.

На самом деле, я просто смотрю на исходный код, чтобы понять, смогу ли я понять это.

6 ответов

Решение

Вот рабочий пример извлечения текста из файла PDF с использованием текущей версии PDFMiner(сентябрь 2016 г.)

from pdfminer.pdfinterp import PDFResourceManager, PDFPageInterpreter
from pdfminer.converter import TextConverter
from pdfminer.layout import LAParams
from pdfminer.pdfpage import PDFPage
from io import StringIO

def convert_pdf_to_txt(path):
    rsrcmgr = PDFResourceManager()
    retstr = StringIO()
    codec = 'utf-8'
    laparams = LAParams()
    device = TextConverter(rsrcmgr, retstr, codec=codec, laparams=laparams)
    fp = open(path, 'rb')
    interpreter = PDFPageInterpreter(rsrcmgr, device)
    password = ""
    maxpages = 0
    caching = True
    pagenos=set()

    for page in PDFPage.get_pages(fp, pagenos, maxpages=maxpages, password=password,caching=caching, check_extractable=True):
        interpreter.process_page(page)

    text = retstr.getvalue()

    fp.close()
    device.close()
    retstr.close()
    return text

Структура PDFMiner недавно изменилась, поэтому это должно работать для извлечения текста из файлов PDF.

Редактировать: Все еще работает с 7 июня 2018 года. Проверено в Python версии 3.x

Это работает в мае 2020 года с использованием PDFminer six на Python3.

Установка пакета

$ pip install pdfminer.six

Импорт пакета

from pdfminer.high_level import extract_text

Использование PDF-файла, сохраненного на диске

text = extract_text('report.pdf')

Или альтернативно:

with open('report.pdf','rb') as f:
    text = extract_text(open('report.pdf','rb'))

Использование PDF уже в памяти

Если PDF-файл уже находится в памяти, например, если он получен из Интернета с помощью библиотеки запросов, его можно преобразовать в поток с помощью io библиотека:

import io

response = requests.get(url)
text = extract_text(io.BytesIO(response.content))

Производительность и надежность по сравнению с PyPDF2

PDFminer.six работает более надежно, чем PyPDF2 (который не работает с некоторыми типами PDF-файлов), в частности PDF версии 1.7.

Однако извлечение текста с помощью PDFminer.six значительно медленнее, чем PyPDF2, в 6 раз.

Я рассчитал извлечение текста с помощью timeit на 15-дюймовом MBP (2018 г.), синхронизируя только функцию извлечения (без открытия файла и т. д.) с 10-страничным PDF-файлом, были получены следующие результаты:

PDFminer.six: 2.88 sec
PyPDF2:       0.45 sec

pdfminer.six также занимает огромную площадь, требуя pycryptodome, для которого требуется установка GCC и других вещей, для чего минимальный установочный образ докера в Alpine Linux составляет от 80 МБ до 350 МБ. PyPDF2 не оказывает заметного влияния на хранилище.

Потрясающий ответ от DuckPuncher, для Python3 убедитесь, что вы установили pdfminer2 и выполните:

import io

from pdfminer.pdfinterp import PDFResourceManager, PDFPageInterpreter
from pdfminer.converter import TextConverter
from pdfminer.layout import LAParams
from pdfminer.pdfpage import PDFPage


def convert_pdf_to_txt(path):
    rsrcmgr = PDFResourceManager()
    retstr = io.StringIO()
    codec = 'utf-8'
    laparams = LAParams()
    device = TextConverter(rsrcmgr, retstr, codec=codec, laparams=laparams)
    fp = open(path, 'rb')
    interpreter = PDFPageInterpreter(rsrcmgr, device)
    password = ""
    maxpages = 0
    caching = True
    pagenos = set()

    for page in PDFPage.get_pages(fp, pagenos, maxpages=maxpages,
                                  password=password,
                                  caching=caching,
                                  check_extractable=True):
        interpreter.process_page(page)

    text = retstr.getvalue()

    fp.close()
    device.close()
    retstr.close()
    return text

Полное раскрытие информации, я являюсь одним из сопровождающих pdfminer.six.

В настоящее время существует несколько API для извлечения текста из PDF, в зависимости от ваших потребностей. За кулисами все эти API используют одну и ту же логику для синтаксического анализа и анализа макета.

Командная строка

Если вы хотите извлечь текст только один раз, вы можете использовать инструмент командной строки pdf2txt.py:

$ pdf2txt.py example.pdf

API высокого уровня

Если вы хотите извлечь текст с помощью Python, вы можете использовать высокоуровневый api. Этот подход является идеальным решением, если вы хотите программно извлекать текст из многих PDF-файлов.

from pdfminer.high_level import extract_text

text = extract_text('samples/simple1.pdf')

Составной API

Также существует составной API, который дает большую гибкость в обработке результирующих объектов. Например, вы можете реализовать свой собственный алгоритм компоновки, используя это. Этот метод предлагается в других ответах, но я бы рекомендовал его только тогда, когда вам нужно настроить поведение pdfminer.six.

from io import StringIO

from pdfminer.converter import TextConverter
from pdfminer.layout import LAParams
from pdfminer.pdfdocument import PDFDocument
from pdfminer.pdfinterp import PDFResourceManager, PDFPageInterpreter
from pdfminer.pdfpage import PDFPage
from pdfminer.pdfparser import PDFParser

output_string = StringIO()
with open('samples/simple1.pdf', 'rb') as in_file:
    parser = PDFParser(in_file)
    doc = PDFDocument(parser)
    rsrcmgr = PDFResourceManager()
    device = TextConverter(rsrcmgr, output_string, laparams=LAParams())
    interpreter = PDFPageInterpreter(rsrcmgr, device)
    for page in PDFPage.create_pages(doc):
        interpreter.process_page(page)

print(output_string.getvalue())

Этот код протестирован с помощью pdfminer для python 3 (pdfminer-20191125)

from pdfminer.layout import LAParams
from pdfminer.converter import PDFPageAggregator
from pdfminer.pdfinterp import PDFResourceManager
from pdfminer.pdfinterp import PDFPageInterpreter
from pdfminer.pdfpage import PDFPage
from pdfminer.layout import LTTextBoxHorizontal

def parsedocument(document):
    # convert all horizontal text into a lines list (one entry per line)
    # document is a file stream
    lines = []
    rsrcmgr = PDFResourceManager()
    laparams = LAParams()
    device = PDFPageAggregator(rsrcmgr, laparams=laparams)
    interpreter = PDFPageInterpreter(rsrcmgr, device)
    for page in PDFPage.get_pages(document):
            interpreter.process_page(page)
            layout = device.get_result()
            for element in layout:
                if isinstance(element, LTTextBoxHorizontal):
                    lines.extend(element.get_text().splitlines())
    return lines

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

Другие вопросы по тегам