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

87

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

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

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

Утиный перфоратор
источник
1
Посетите stackoverflow.com/help/how-to-ask и stackoverflow.com/help/mcve и обновите свой ответ, чтобы он был в лучшем формате и соответствовал рекомендациям.
Паркер
Какой дистрибутив Python вы используете, 2.7.x или 3.xx? Следует отметить, что автор подробно описал, что PDFminerне работает с Python 3.xx. Это может быть причиной того, что вы получаете importошибки. Вы должны использовать, pdfminer3kесли это так, поскольку это постоянный импорт Python 3 указанной библиотеки.
NullDev
@Nanashi, извини, я забыл добавить свою версию Python. Это 2.7, так что проблема не в этом. Я просматривал исходный код, и похоже, что они реструктурировали некоторые вещи, поэтому импорт ломается. Я также не могу найти никакой документации для PDFMiner, иначе я бы просто работал над этим :(
DuckPuncher
Я только что буквально установил PDFminerс GitHub, и он отлично импортирует. Можете ли вы опубликовать свой код и полную трассировку ошибок?
NullDev
@Nanashi, Как я уже сказал в своем первоначальном вопросе, библиотеки, которые полагаются на PDFMiner, прерываются перед завершением импорта вместе с любыми примерами, которые я могу найти. Это не проблема PDFMiner. Это я ищу документацию или пример использования PDFMiner. Все, что я могу найти, это использование старого синтаксиса PDFMiner. Я пошел дальше и отредактировал свой вопрос для ясности. Думаю, я сделал это более запутанным, чем нужно. Прости за это.
DuckPuncher

Ответы:

182

Вот рабочий пример извлечения текста из файла 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

Изменить: решение работает с Python 3.7 от 3 октября 2019 г. Я использовал библиотеку Python pdfminer.six, выпущенную в ноябре 2018 г.

Утиный перфоратор
источник
2
работает нормально, но как я могу работать с пробелами, например, в именах? Предположим, у меня есть PDF-файл, содержащий 4 столбца, где у меня есть имя и фамилия в одном столбце, теперь он анализируется с именем в одной строке и фамилией в одной строке, вот пример docdro.id/rRyef3x
Deusdeorum
2
В настоящее время возникает ошибка импорта с этим кодом: ImportError: Нет модуля с именем pdfminer.pdfpage
Джеффри Свон,
1
Спасибо, он работает на python v2.7.12 и на ubuntu 16.04, хотя было бы лучше загрузить документ pdf с кодировкой utf-8, потому что у моего образца pdf есть некоторые проблемы с кодировкой, поэтому попробуйте это после кодирования с помощью utf-8, и это решит выпуск ... import sys reload(sys) sys.setdefaultencoding('utf-8')
sib10
2
@DuckPuncher, он еще работает? Мне пришлось изменить на file(path, 'rb')`open (path, 'rb'), чтобы мой заработал.
вытянули
2
Все еще работает для пользователей Python3.7. Установлен пакет pdfminer.six == 20181108. Лучшее решение для моего случая, и я сравнил множество решений.
aze45sq6d 05
29

потрясающий ответ от 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)



    fp.close()
    device.close()
    text = retstr.getvalue()
    retstr.close()
    return text
Хуан Исаза
источник
1
У меня это не работает: ModuleNotFoundError: Нет модуля с именем pdfminer.pdfpage, я использую python 3.6
Атти
@Atti, на всякий случай убедитесь, что у вас установлен pdfminer2, так как есть еще один пакет pdfminer (ненавижу это). Он работает для версии pdfminer2 == 20151206 при замораживании pip3.
хуан Исас
5
спасибо, у меня все заработало, я установил pdfminer.six из conda forge
Атти,
8
Для Python 3 рекомендуется использовать pdfminer.six - github.com/pdfminer/pdfminer.six
Майк Дрисколл,
Это все еще актуально. У меня такое же ImportError:сообщение
12

Это работает в мае 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 не оказывает заметного влияния на хранилище.

Корнелиус Ремер
источник
Этот подход мог не работать с момента последнего обновления. В настоящее время появляется сообщение об ошибке ImportError: cannot import name 'open_filename' from 'pdfminer.utils'при запускеfrom pdfminer.high_level import extract_text
Дополнительная информация
Обновление: я исправил это, создав новый venv и переустановив pdfminer.six. Я предполагаю, что один из других пакетов pdf, которые я пробовал ранее, как-то мешал.
Дополнительная литература
9

Полное раскрытие информации, я являюсь одним из сопровождающих 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())
Питер
источник
0

этот код протестирован с помощью 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
Brault Gilbert
источник
У меня есть файлы PDF, которые я могу преобразовать с помощью инструмента Nitro Pro. Однако когда я пытаюсь преобразовать тот же PDF-файл, используя размещенный здесь код, я получаю вывод, который предполагает наличие ошибки разрешений. Вот результат: ('из SAGE Social Science Collections. Все права защищены. \ N \ n \ x0c \ x0c \ x0c \ x0c \ x0c \ x0c \ x0c \ x0c \ x0c \ x0c \ x0c \ x0c \ x0c \ x0c \ x0c \ x0c \ x0c \ x0c \ x0c \ x0c \ x0c \ x0c \ x0c \ x0c \ x0c \ x0c \ x0c \ x0c \ x0c ')
b00kgrrl
Что значит файловый поток?
Винсент
@Vincent с open (file, 'rb') в качестве потока: [...]
Родриго Формигьери
получается в идеале получить этот файл в виде таблицы / панд? groupe-psa.com/en/publication/monthly-world-sales-march-2020
Ноно Лондон