Витягування тексту з PDF-файлу за допомогою PDFMiner у python?


87

Я шукаю документацію або приклади того, як витягти текст з PDF-файлу за допомогою PDFMiner з Python.

Схоже, PDFMiner оновив свій API, і всі відповідні приклади, які я знайшов, містять застарілий код (класи та методи змінилися). Знайдені мною бібліотеки, які полегшують завдання вилучення тексту з файлу PDF, використовують старий синтаксис PDFMiner, тому я не знаю, як це зробити.

Так воно і є, я просто розглядаю вихідний код, щоб зрозуміти, чи можу я це зрозуміти.


1
Будь ласка, перевірте stackoverflow.com/help/how-to-ask та stackoverflow.com/help/mcve та оновіть свою відповідь, щоб вона була у кращому форматі та відповідала вимогам.
Parker

Який дистрибутив 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

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,

@Atti, про всяк випадок переконайтесь, що у вас встановлений pdfminer2, оскільки існує інший пакет pdfminer (я ненавиджу це). Він працює для версії pdfminer2 == 20151206 під час заморозки pip3.
Juan Isaza

5
спасибі, що я врешті-решт запрацював, я встановив pdfminer.six з conda forge
Атті,

8
Для Python 3 рекомендується пакет 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

У мене є файли PDF, які я можу конвертувати за допомогою інструмента Nitro Pro. Однак, коли я намагаюся конвертувати той самий PDF за допомогою розміщеного тут коду, я отримую вихідні дані, які свідчать про помилку дозволів. Ось результат: ('з колекцій соціальних наук SAGE. Усі права захищено. \ 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 з відкритим (файл, 'rb') як потік: [...]
Родріго Форміг'єрі

вам вдається отримати цей файл як таблицю / панди в ідеалі? groupe-psa.com/en/publication/monthly-world-sales-march-2020
Nono London
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.