Рубрики
Без рубрики

Экспорт данных из PDFS с Python

Получите практические, реальные навыки Python на наших ресурсах и пути

Автор оригинала: Mike Driscoll.

Есть много раз, когда вы захотите извлечь данные из PDF и экспортировать его в другой формат с помощью Python. К сожалению, не так много пакетов Python, которые очень хорошо выполняют добычу. В этой главе мы рассмотрим множество различных пакетов, которые вы можете использовать для извлечения текста. Мы также узнаем, как извлечь некоторые изображения из PDFS. Хотя в Python нет полного решения для этих задач, вы должны быть в состоянии использовать информацию здесь, чтобы начать. Как только мы извлекли данные, которые мы хотим, мы также посмотрим, как мы можем принять эти данные и экспортировать его в другой формат.

Давайте начнем, узнав, как извлечь текст!

Извлечение текста с pdfminer

Наверное, самым известным является пакет под названием Pdfminer Отказ Пакет PDFMINER был рядом с Python 2.4. Основная цель – извлечь текст из PDF. Фактически, pdfminer может сказать вам точное местоположение текста на странице, а также отца информацию о шрифтах. Для Python 2.4 – 2.7 вы можете ссылаться на следующие сайты для получения дополнительной информации о PDFMiner:

PDFMiner не совместим с Python 3. К счастью, есть вилка PDFMiner под названием Pdfminer.six Это работает точно так же. Вы можете найти это здесь: https://github.com/pdfminer/pdfminer.six.

Хотите узнать больше о работе с PDFS в Python? Затем проверьте мою книгу: REPORTLAB: PDF Обработка с покупкой Python Now на ScenPub

Направления для установки PDFMiner в лучшем случае устарели. Вы действительно можете использовать PIP, чтобы установить его:

python -m pip install pdfminer

Если вы хотите установить PDFMiner для Python 3 (что вы, вероятно, должны делать), то вам нужно сделать такую установку:

python -m pip install pdfminer.six

Документация на PDFMiner довольно плохой в лучшем случае. Скорее всего, вам нужно будет использовать Google и Stackoverflow, чтобы выяснить, как использовать PDFMiner эффективно вне того, что покрывается в этой главе.

Извлечение всего текста

Иногда вы захотите извлечь весь текст в PDF. Пакет PDFMINER предлагает пару различных методов, которые вы можете сделать это. Мы будем смотреть на некоторые из программных методов сначала. Давайте попробуем прочитать все текст из формы внутреннего дохода W9. Вы можете получить копию здесь: https://www.irs.gov/pub/irs-pdf/fw9.pdf.

Как только у вас будет PDF правильно спасено, мы можем посмотреть код:

import io

from pdfminer.converter import TextConverter
from pdfminer.pdfinterp import PDFPageInterpreter
from pdfminer.pdfinterp import PDFResourceManager
from pdfminer.pdfpage import PDFPage

def extract_text_from_pdf(pdf_path):
    resource_manager = PDFResourceManager()
    fake_file_handle = io.StringIO()
    converter = TextConverter(resource_manager, fake_file_handle)
    page_interpreter = PDFPageInterpreter(resource_manager, converter)
    
    with open(pdf_path, 'rb') as fh:
        for page in PDFPage.get_pages(fh, 
                                      caching=True,
                                      check_extractable=True):
            page_interpreter.process_page(page)
            
        text = fake_file_handle.getvalue()
    
    # close open handles
    converter.close()
    fake_file_handle.close()
    
    if text:
        return text
    
if __name__ == '__main__':
    print(extract_text_from_pdf('w9.pdf'))

Пакет PDFMINER имеет тенденцию быть немного многословным при использовании его напрямую. Здесь мы импортируем различные биты и кусочки из разных частей PDFMiner. Поскольку нет документации по любому из этих классов и никаких докладов, я не объясню, что они в глубине. Не стесняйтесь копать исходным кодом самостоятельно, если вы действительно любопытно. Тем не менее, я думаю, что мы можем отказаться от кода.

Первое, что мы делаем, это создать экземпляр менеджера ресурсов. Затем мы создаем файловый объект через Python’s Ио модуль. Если вы используете Python 2, то вы захотите использовать Stringio модуль. Наш следующий шаг – создать конвертер. В этом случае мы выбираем TextConverter Однако, однако, вы также можете использовать HTMLConverter или Xmlconverter Если вы хотели. Наконец, мы создаем объект интерпретатора PDF, который займет наш ресурсный менеджер и объекты преобразователя и извлекает текст.

Последний шаг – открыть PDF и LOOP через каждую страницу. В конце мы снимаем весь текст, закрываем различные обработчики и распечатайте текст на STDOUT.

Извлечение текста по странице

Честно говоря, захватывающий весь текст из многостраничного документа, не так и не так полезно. Обычно вы захотите работать на меньших подмножестве документа. Итак, давайте переписываем код, чтобы извлечь текст на основе страниц страницы. Это позволит нам проверить текст на страницу за раз:

# miner_text_generator.py

import io

from pdfminer.converter import TextConverter
from pdfminer.pdfinterp import PDFPageInterpreter
from pdfminer.pdfinterp import PDFResourceManager
from pdfminer.pdfpage import PDFPage

def extract_text_by_page(pdf_path):
    with open(pdf_path, 'rb') as fh:
        for page in PDFPage.get_pages(fh, 
                                      caching=True,
                                      check_extractable=True):
            resource_manager = PDFResourceManager()
            fake_file_handle = io.StringIO()
            converter = TextConverter(resource_manager, fake_file_handle)
            page_interpreter = PDFPageInterpreter(resource_manager, converter)
            page_interpreter.process_page(page)
            
            text = fake_file_handle.getvalue()
            yield text
    
            # close open handles
            converter.close()
            fake_file_handle.close()
    
def extract_text(pdf_path):
    for page in extract_text_by_page(pdf_path):
        print(page)
        print()
        
if __name__ == '__main__':
    print(extract_text('w9.pdf'))

В этом примере мы создаем функцию генератора, что Урожайность текст для каждой страницы. Extract_Text Функция печатает текст каждой страницы. Именно здесь мы могли бы добавить какую-то разборную логику для того, чтобы разбирать то, что мы хотим. Или мы могли бы просто сохранить текст (или HTML или XML), как отдельные файлы для будущего анализа.

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

Приятная вещь о PDFMiner заключается в том, что вы уже можете «экспортировать» PDF в виде текста, HTML или XML.

Вы также можете использовать инструменты командной строки PDFMINER, pdf2txt.py и dumppdf.py Чтобы сделать экспорт для вас, если вы не хотите пытаться выяснить PDFMiner самостоятельно. Согласно исходному коду pdf2txt.py , его можно использовать для экспорта PDF в виде простого текста, HTML, XML или «тегов».

Экспорт текста через pdf2txt.py

pdf2txt.py Инструмент командной строки, который поставляется с PDFMiner, будет извлекать текст из файла PDF и по умолчанию распечатает его на STDOUT. Он не распознает текст, который представляет собой изображения, так как PDFMiner не поддерживает распознавание оптического символа (OCR). Давайте попробуем простейший метод использования его, который просто передает его путь к файлу PDF. Мы будем использовать W9.PDF Отказ Откройте терминал и перейдите к расположению, которое вы сохранили, чтобы PDF или измените команду ниже, чтобы указать на этот файл:

pdf2txt.py w9.pdf

Если вы запустите это, он распечатает весь текст на STDOUT. Вы также можете сделать PDF2TXT.PY написать текст в файл в виде текста, HTML, XML или «помеченных PDF». Формат XML предоставит большему количеству информации о PDF, поскольку она содержит местоположение каждой буквы в документе, а также информацию о шрифте. HTML не рекомендуется, поскольку Markup PDF2TXT генерирует, имеет тенденцию быть уродливыми. Вот как вы можете получить разные форматы вывода:

pdf2txt.py -o w9.html w9.pdf 
pdf2txt.py -o w9.xml w9.pdf 

Первая команда создаст HTML-документ, когда второй создаст документ XML. Вот сченшот того, что я получил, когда сделал преобразование HTML:

Как видите, конечный результат выглядит немного отключено, но это не так уж плохо. Выводы XML IT очень многословны, поэтому я не могу воспроизвести все это здесь. Однако вот фрагмент, чтобы дать вам представление о том, как выглядит так:

[XML] F o r m W – 9

Извлечение текста с шифером

Тим Макнамара не понравилась, как тупые и сложные PDFMiner используют, поэтому он написал оболочку вокруг него шифер Это делает намного проще извлечь текст от PDFS. К сожалению, оно не является совместимым Python 3. Если вы хотите попробовать, вам может понадобиться easy_install Доступно для установки распределить Пакет, как это:

easy_install distribute

Я не смог получить PiP, чтобы установить этот пакет правильно. После того, как он будет установлен, вы сможете использовать PIP для установки Slate:

python -m pip install slate

Обратите внимание, что последняя версия 0.5.2 и PIP может или не может захватить эту версию. Если это не так, то вы можете установить сланца прямо из GitHub:

python -m pip install git+https://github.com/timClicks/slate

Теперь мы готовы написать какой-нибудь код для извлечения текста из PDF:

# slate_text_extraction.py

import slate

def extract_text_from_pdf(pdf_path):
    with open(pdf_path) as fh:
        document = slate.PDF(fh, password='', just_text=1)
    
    for page in document:
        print(page)
        
if __name__ == '__main__':
    extract_text_from_pdf('w9.pdf')

Как видите, чтобы сделать Slate Parse PDF, вам просто нужно импортировать Slate, а затем создать экземпляр его PDF класс. Класс PDF на самом деле является подклассом Python’s Список Встроенный, так что он просто возвращает список/утилизируемых страниц текста. Вы также отметите, что мы можем пройти в аргументе пароля, если PDF имеет набор паролей. В любом случае, после того, как документ проанализирован, мы просто распечатаны текст на каждой странице.

Мне очень нравится, насколько легче использовать сланца. К сожалению, нет практически никакой документации, связанной с этим пакетом. После просмотра исходного кода, кажется, что все это поддерживает пакет – это извлечение текста.

Экспорт ваших данных

Теперь, когда у нас есть какой-то текст для работы, мы проведем некоторое время на изучение того, как экспортировать эти данные в различных форматах. В частности, мы узнаем, как экспортировать наш текст следующими способами:

  • XML
  • Json.
  • CSV

Давайте начнем!

Экспорт в XML.

Формат расширяемого языка разметки (XML) является одним из самых известных выходных и входных форматов. Он широко используется в Интернете для многих разных вещей. Как мы уже видели в этой главе, PDFminer также поддерживает XML как один из его выходов.

Давайте создадим наш собственный инструмент для создания XML. Вот простой пример:

# xml_exporter.py

import os
import xml.etree.ElementTree as xml

from miner_text_generator import extract_text_by_page
from xml.dom import minidom


def export_as_xml(pdf_path, xml_path):
    filename = os.path.splitext(os.path.basename(pdf_path))[0]
    root = xml.Element('{filename}'.format(filename=filename))
    pages = xml.Element('Pages')
    root.append(pages)
    
    counter = 1
    for page in extract_text_by_page(pdf_path):
        text = xml.SubElement(pages, 'Page_{}'.format(counter))
        text.text = page[0:100]
        counter += 1
    
    tree = xml.ElementTree(root)
    xml_string = xml.tostring(root, 'utf-8')
    parsed_string = minidom.parseString(xml_string)
    pretty_string = parsed_string.toprettyxml(indent='  ')
    
    with open(xml_path, 'w') as fh:
        fh.write(pretty_string)
    #tree.write(xml_path)

if __name__ == '__main__':
    pdf_path = 'w9.pdf'
    xml_path = 'w9.xml'
    export_as_xml(pdf_path, xml_path)

Этот скрипт будет использовать встроенные библиотеки XML Python, Минизм и ElementTree Отказ Мы также импортируем наш сценарий генератора PDFMINER, который мы используем для захвата страницы текста одновременно. В этом примере мы создаем наш элемент верхнего уровня, который является именем файла PDF. Тогда мы добавляем Страницы Элемент под ним. Следующий шаг – наше для Цикл, где мы извлекаем каждую страницу из PDF и сохранить информацию, которую мы хотим. Вот где вы можете добавить специальный анализатор, где вы можете разделить страницу в предложения или слова и проанализировать более интересную информацию. Например, вы можете захотеть только предложения с определенным именем или дату/временем. Вы можете использовать регулярные выражения Python, чтобы найти такие вещи или просто проверить наличие субклагонов в предложении.

Для этого примера мы просто извлекаем первые 100 символов с каждой страницы и сохраняйте их в XML Подселемент Отказ Технически следующий код кода может быть упрощен, чтобы просто выписать XML. Тем не менее, ElectionTree не делает ничего для XML, чтобы легко прочитать. Это как будто выглядит как министерзированный JavaScript в том, что он только один гигантский блок текста. Поэтому вместо того, чтобы писать этот блок текста на диск, мы используем Минизм Чтобы «претеннуть» XML с пробелом, прежде чем написать его. Результат в конечном итоге выглядит так:

[XML] XML? Форма W-9 (Rev. Ноябрь 2017 г.) Департамент запроса службы внутреннего дохода казначейства на Taxp Форма W-9 (Rev. 11-2017) Page 2, подписав заполненную форму, вы: 1. Убедитесь, что олово вы G Форма W-9 (Rev. 11-2017) Page 3 Уголовное наказание на фальсификацию информации. Умышленно фальсификация сертификата Форма W-9 (Rev. 11-2017) Page 4 Следующая графика показывает типы платежей, которые могут быть освобождены от BA Форма W-9 (Rev. 11-2017) Page 5 1. Проценты, дивидендные и бартерные биржевые счета были открыты до 1984 года Форма W-9 (Rev. 11-2017) Page 6 IRS не инициирует контакты с налогоплательщиками по электронной почте. Кроме того, This.

Это довольно чисто XML, и это также легко читать. Для бонусных баллов вы можете взять то, что вы узнали в главе PypDF2 и используете его для извлечения метаданных из PDF и добавить его в свой XML.

Экспорт в JSON

Обзор JavaScript или JSON – это легкий формат передачи данных, который легко читает и запись. Python включает в себя JSON Модуль в своей стандартной библиотеке, которая позволяет прочитать и писать JSON программно. Давайте возьмем то, что мы узнали из предыдущего раздела и используйте это для создания сценария экспортера, который выводит JSON вместо XML:

# json_exporter.py

import json
import os

from miner_text_generator import extract_text_by_page


def export_as_json(pdf_path, json_path):
    filename = os.path.splitext(os.path.basename(pdf_path))[0]
    data = {'Filename': filename}
    data['Pages'] = []
    
    counter = 1
    for page in extract_text_by_page(pdf_path):
        text = page[0:100]
        page = {'Page_{}'.format(counter): text}
        data['Pages'].append(page)
        counter += 1
    
    with open(json_path, 'w') as fh:
        json.dump(data, fh)

if __name__ == '__main__':
    pdf_path = 'w9.pdf'
    json_path = 'w9.json'
    export_as_json(pdf_path, json_path)

Здесь мы импортируем различные библиотеки, которые нам нужны, включая наш модуль PDFMINER. Затем мы создаем функцию, которая принимает путь ввода PDF и путь вывода JSON. JSON в основном словарь в Python, поэтому мы создаем пару простых клавиш верхнего уровня: Имя файла и Страницы Отказ Страницы Основные карты в пустой список. Далее мы цикла по каждую страницу PDF и извлеките первые 100 символов каждой страницы. Затем мы создаем словарь с номером страницы в качестве ключа и 100 символов как значение, и добавьте его в список страниц верхнего уровня. Наконец мы пишем файл, используя JSON модуль Дамп команда.

Содержимое файла завершилось так:

{'Filename': 'w9',
 'Pages': [{'Page_1': 'Form    W-9(Rev. November 2017)Department of the Treasury  Internal Revenue Service Request for Taxp'},
           {'Page_2': 'Form W-9 (Rev. 11-2017)Page 2 By signing the filled-out form, you: 1. Certify that the TIN you are g'},
           {'Page_3': 'Form W-9 (Rev. 11-2017)Page 3 Criminal penalty for falsifying information. Willfully falsifying cert'},
           {'Page_4': 'Form W-9 (Rev. 11-2017)Page 4 The following chart shows types of payments that may be exempt from ba'},
           {'Page_5': 'Form W-9 (Rev. 11-2017)Page 5 1. Interest, dividend, and barter exchange accounts opened before 1984'},
           {'Page_6': 'Form W-9 (Rev. 11-2017)Page 6 The IRS does not initiate contacts with taxpayers via emails. Also, th'}]}

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

Теперь давайте посмотрим на то, как мы могли бы экспортировать в CSV.

Экспорт в CSV.

CSV означает ** значения разделенных запятыми **. Это довольно стандартный формат, который был очень долго. Приятная вещь о CSV в том, что Microsoft Excel и LibreOffice откроют их в приятной электронной таблице автоматически. Вы также можете открыть файлы CSV в текстовом редакторе, если вы хотите увидеть необработанное значение.

У Python есть встроенный CSV Модуль, который вы можете использовать для чтения и записи файлов CSV. Мы будем использовать его здесь, чтобы создать CSV из текста, который мы извлекаем из PDF. Давайте посмотрим на какой-то код:

# csv_exporter.py

import csv
import os

from miner_text_generator import extract_text_by_page


def export_as_csv(pdf_path, csv_path):
    filename = os.path.splitext(os.path.basename(pdf_path))[0]
    
    counter = 1
    with open(csv_path, 'w') as csv_file:
        writer = csv.writer(csv_file)
        for page in extract_text_by_page(pdf_path):
            text = page[0:100]
            words = text.split()
            writer.writerow(words)
            
        
if __name__ == '__main__':
    pdf_path = 'w9.pdf'
    csv_path = 'w9.csv'
    export_as_csv(pdf_path, csv_path)

Для этого примера мы импортируем Python’s CSV библиотека. В противном случае импорт такой же, как предыдущий пример. В нашей функции мы создаем обработчик файла CSV, используя путь к файлу CSV. Затем мы инициализируем объект писателя CSV с помощью этого обработчика файлов в качестве единственного аргумента. Далее мы циклируем на страницах PDF как раньше. Единственная разница вот в том, что мы разделяем первые 100 символов в отдельные слова. Это позволяет нам иметь некоторые фактические данные для добавления в CSV. Если мы этого не сделали, то каждый ряд будет иметь только один элемент в нем, который на самом деле не является файлом CSV в этой точке. Наконец мы выписываем наш список слов в файл CSV.

Это результат, который я получил:

Form,W-9(Rev.,November,2017)Department,of,the,Treasury,Internal,Revenue,Service,Request,for,Taxp
Form,W-9,(Rev.,11-2017)Page,2,By,signing,the,filled-out,"form,",you:,1.,Certify,that,the,TIN,you,are,g
Form,W-9,(Rev.,11-2017)Page,3,Criminal,penalty,for,falsifying,information.,Willfully,falsifying,cert
Form,W-9,(Rev.,11-2017)Page,4,The,following,chart,shows,types,of,payments,that,may,be,exempt,from,ba
Form,W-9,(Rev.,11-2017)Page,5,1.,"Interest,","dividend,",and,barter,exchange,accounts,opened,before,1984
Form,W-9,(Rev.,11-2017)Page,6,The,IRS,does,not,initiate,contacts,with,taxpayers,via,emails.,"Also,",th

Я думаю, что это немного сложнее читать, чем примеры JSON или XML, но это не так уж плохо. Теперь давайте перейдем и посмотрим, как мы можем извлечь изображения из PDF.

Извлечение изображений из PDFS

К сожалению, нет пакетов Python, которые на самом деле делают добычу изображения от PDFS. Самое близкое, что я нашел, был проектом под названием Minecart Это утверждает, что сможет это сделать, но работает только на Python 2.7. Я не смог заставить его работать с образцами PDFS, которые у меня было. Есть статья о NED Batchelder’s Блог Это немного говорит о том, как он смог извлечь JPG из PDFS. Его код выглядит следующим образом:

# Extract jpg's from pdf's. Quick and dirty.
import sys

pdf = file(sys.argv[1], "rb").read()

startmark = "\xff\xd8"
startfix = 0
endmark = "\xff\xd9"
endfix = 2
i = 0

njpg = 0
while True:
    istream = pdf.find("stream", i)
    if istream < 0:
        break
    istart = pdf.find(startmark, istream, istream+20)
    if istart < 0:
        i = istream+20
        continue
    iend = pdf.find("endstream", istart)
    if iend < 0:
        raise Exception("Didn't find end of stream!")
    iend = pdf.find(endmark, iend-20)
    if iend < 0:
        raise Exception("Didn't find end of JPG!")
    
    istart += startfix
    iend += endfix
    print("JPG %d from %d to %d" % (njpg, istart, iend))
    jpg = pdf[istart:iend]
    jpgfile = file("jpg%d.jpg" % njpg, "wb")
    jpgfile.write(jpg)
    jpgfile.close()
    
    njpg += 1
    i = iend

Это также не работало для PDF, которые я использовал. В комментариях есть некоторые люди, которые требуют, это работает для некоторых их PDF, и в комментариях также есть несколько примеров обновленного кода. StackoverFlow имеет вариации этого кода на нем, некоторые из которых используют PYPDF2 так или иначе. Никто из них тоже не работал для меня.

Моя рекомендация – использовать инструмент, похожий на Poppler Чтобы извлечь изображения. Poppler имеет инструмент под названием pdfimages что вы можете использовать с Python’s подпрокат модуль. Вот как вы могли бы использовать его без Python:

pdfimages -all reportlab-sample.pdf images/prefix-jpg

Убедитесь, что Изображения Папка (или любой выходной папка, которую вы хотите создать), уже создан, поскольку PDFImages не создает его для вас.

Давайте напишем сценарий Python, который также выполняет эту команду и убедитесь, что выводящая папка тоже существует:

# image_exporter.py

import os
import subprocess

def image_exporter(pdf_path, output_dir):
    if not os.path.exists(output_dir):
        os.makedirs(output_dir)
        
    cmd = ['pdfimages', '-all', pdf_path, 
           '{}/prefix'.format(output_dir)]
    subprocess.call(cmd)
    print('Images extracted:')
    print(os.listdir(output_dir))
    

if __name__ == '__main__':
    pdf_path = 'reportlab-sample.pdf'
    image_exporter(pdf_path, output_dir='images')

В примере в твоем примере мы импортируем подпрокат и ОС модули. Если выходной каталог не существует, мы пытаемся создать его. Их мы используем подпроцесс Позвоните Способ выполнения pdfimages. Мы используем Позвоните Потому что он будет ждать pdfimages, чтобы закончить работу. Вы могли бы использовать Popen Вместо этого, но это будет в основном запускать процесс на заднем плане. Finaly Мы распечатаем список выходных каталога для подтверждения того, что изображения были извлечены к нему.

Есть некоторые другие статьи в Интернете, что ссылается на библиотеку под названием Палочка что вы также можете попробовать. Это обертка ImageMagick. Также от примечания заключается в том, что есть привязка Python с Pop-Top Site Pypoppler , хотя я не смог найти какие-либо примеры этого пакета, который сделал добычу изображения.

Обертывание

Мы охватываем много разной информации в этой главе. Вы узнали о нескольких разных пакетах, которые мы можем использовать для извлечения текста из PDFS, таких как PDFMiner или Slate. Мы также узнали, как использовать встроенные библиотеки Python для экспорта текста на XML, JSON и CSV. Наконец мы посмотрели на сложные проблемы экспорта изображений из PDFS. В то время как Python в настоящее время не имеет хороших библиотек для этой задачи, вы можете обработать это, используя другие инструменты, такие как утилита PDFImage POPPLER.

Связанное чтение