Экспортируем данные из PDF при помощи Python

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

Есть вопросы по Python?

На нашем форуме вы можете задать любой вопрос и получить ответ от всего нашего сообщества!

Telegram Чат & Канал

Вступите в наш дружный чат по Python и начните общение с единомышленниками! Станьте частью большого сообщества!

Паблик VK

Одно из самых больших сообществ по Python в социальной сети ВК. Видео уроки и книги для вас!

Начнем с того, как извлекать текст!

Извлечение Текста с 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

Инструкции по установке PDFMiner как минимум можно назвать устаревшими. Вы можете использовать pip для проведения установки:

Если вам нужно установить PDFMiner в Python 3 (что вы, скорее всего, и пытаетесь сделать), то вам нужно провести установку следующим образом:

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

Извлекаем весь текст

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

После удачного сохранения PDF файла, мы можем взглянуть на код:

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

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

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

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

Честно говоря, брать весь текст из многостраничного документа далеко не всегда оказывается полезным. Как правило, вам может понадобиться работать с отдельными фрагментами документа. Давайте перепишем код таким образом, чтобы он извлекал текст постранично. Это позволит нам проверить текст (страница за раз):

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

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

Хороший момент в работе с PDFMiner: вы можете сразу экспортировать PDF в формате текста, HTML или XML.

Вы также можете использовать инструменты командной строки PDFMiner, pdf2txt.py и dumppdf.py для проведения экспорта, если не хотите разбирать PDFMiner лично. Согласно с исходным кодом pdf2txt.py (https://github.com/euske/pdfminer/blob/master/tools/pdf2txt.py), его можно использовать для экспорта PDF в сплошной текст, html или xml.

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

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

Если вы запустите это команду, она выведет весь текст в stdout. Вы также можете сделать так, чтобы pdf2txt.py записывал текст в файл в качестве текста, HTML или XML. Формат XML даст много информации о PDF файле, так как хранит в себе расположение каждой буквы в документе, а также информацию о шрифтах.

HTML не рекомендуется, так как разметка, генерируемая pdf2txt, скорее всего будет выглядеть не очень хорошо. Посмотрим, как получить выдачу в различных форматах:

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

Экспортируем данные из PDF при помощи Python

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

Извлечение текста при помощи Slate

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

У меня не вышло сделать так, чтобы pip устанавливал этот пакет правильно. После того, как вы его установите, вы, тем не менее, сможете установить slate через pip:

Обратите внимание на то, что последней версией является 0.5.2, так что pip может потянуть её, а может и не потянуть. Если не потянул, то вы можете установить slate прямо с Github:

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

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

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

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

Теперь, когда мы получили текст, с которым можно работать, мы уделим немного времени тому, чтобы понять, как экспортировать эти данные в ряд различных форматов, а именно:

  • XML
  • JSON
  • CSV

Приступим!

Экспорт в XML

Формат eXtensible Markup Language (XML) – это один из самых известных форматов ввода и вывода. Он широко используется в интернете для различных целей. Как мы уже видели в этой статье, PDFMiner также поддерживает XML в качестве одного из вариантов выдачи.

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

Этот скрипт будет использовать встроенные библиотеки XML: minidom и ElementTree. Мы также импортируем скрипт генератора PDFMiner, который мы используем для того, чтобы выделять текст постранично. В данном примере, мы создадим элемент высшего уровня, который является названием файла PDF. Далее, мы добавляем элемент Pages под ним. После этого, переходим к циклу for, где мы извлекаем каждую страницу PDF и сохраняем информацию, которая нам нужна. Здесь вы можете добавить специальный парсер, в котором вы можете разделить страницу на предложения или слова и парсить более интересную информацию. Например, вам могут понадобиться предложения с определенным именем, данными, указанным временем. Вы можете использовать регулярные выражения Python для поиска, или проверить наличие наследуемых строк в предложении.

Для этого примера мы просто извлечем 100 символов из каждой страницы и сохраним их в SubElement XML. Технически, следующая часть кода может быть упрощена, чтобы просто вписать XML. Однако, ElementTree ничего не делает с XML, чтобы сделать его читабельным. Это больше похоже на минимизированный javascript: просто большой блок текста.

Так что вместо того, чтобы вписывать этот блок текста в диск, мы используем minidom, чтобы облагородить XML пробелами, перед тем как сохранять. Результат должен выглядеть следующим образом:

Это делает XML чище и более читабельным. В качестве бонуса, вы также можете воспользоваться методом извлечения метадаты из PDF и добавить её в свой PDF при помощи PyPDF2.

Экспорт PDF в JSON

JavaScript Object Notation, или JSON, представляет собой простой формат обмены данными, который легко читать и писать. Python содержит модуль json в своей стандартной библиотеки, который позволяет вам программно читать и писать в JSON. Давайте посмотрим, что мы усвоили из предыдущего раздела и используем это для создания скрипта экспорта, который выдает JSON вместо XML:

Здесь мы импортируем различные библиотеки, которые нам могут понадобиться, включая модуль PDFMiner. Далее, мы создаем функцию, которая принимает путь ввода PDF и путь выдачи JSON. JSON – это, фактически, словарь в Python, так что мы создаем несколько простых ключей высшего уровня: Filename и Pages. Ключ Pages сопоставляется с пустым списком. Далее, мы вводим цикл над каждой страницей PDF и извлекаем первые 100 символов каждой страницы. Далее, мы создаем словарь с номером страницы в качестве ключа и 100 символов в качестве значение и добавим в список верхнего уровня Page. Наконец, мы записываем файл при помощи команды модуля json под названием dump.

Содержимое файла должно выглядеть следующим образом:

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

Давайте посмотрим, как мы можем проводить экспорт в CSV.

Экспорт PDF в CSV

CSV значит Comma Separated Values (значения, разделенные запятой). Это достаточно простой формат, который существует уже продолжительное время. Хороший момент работы с CSV, это то, что Microsoft Excel и LibreOffice могут открывать его в красивой таблице автоматически. Вы также можете открывать файлы CSV в редакторе текстов, если вы хотите увидеть исходное значение.
Python содержит встроенный модуль csv, который вы можете использовать для написания и чтения файлов CSV. Мы используем его здесь для создания CSV из текста, который мы извлекаем из PDF. Давайте посмотрим на код:

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

Мы должны получить следующий результат:

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

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

К сожалению, не существует пакетов Python, которые выполняют извлечение изображений из PDF. Наиболее близкий проект, который я нашел – это minecart, который может делать это, но он работает только на Python 2.7. У меня не вышло его запустить при работе с примером PDF, который у меня был. Однако есть способ, который позволяет извлекать JPG из PDF. Вот пример кода:

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

Я рекомендую использовать инструмент Poppler для извлечения изображений. Poppler включает в себя инструмент под названием pdfimages, который вы можете использовать с модулем Python под названием subprocess. Вот как использовать его без Python:

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

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

В этом примере мы импортировали модули subprocess и os. Если папка выдачи не существует, мы попытаемся создать её. Далее мы используем метод вызова subprocess для запуска pdfimages. Мы используем вызов, так как он будет ожидать pdfimages, пока тот закончит работу. Вы можете использовать Popen вместо этого, но это фактически запускает процесс в фоновом режиме. Наконец, мы выводим список папки выдачи для подтверждения того, что изображения были добавлены в неё.

Есть статьи, которые ссылаются на библиотеку под названием Wand, которую вы тоже можете попробовать. Это оболочка ImageMagick. Также обратите внимание на то, что существует связка Python с Poppler под названием pypoppler, однако я не нашел примеров того, что этот пакет выполняет извлечение изображений.

Подведем итоги

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