Извлечение текста из файла 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, который в настоящее время поддерживается.