Что найти?

Чтение, извлечение и разделение страниц в PDF-файлах Python

/
/

Сегодня Portable Document Format (PDF) относится к наиболее часто используемым форматам данных. В 1990 году структура документа PDF была определена компанией Adobe. Идея формата PDF заключается в том, что передаваемые данные и документы выглядят одинаково для обеих сторон, участвующих в процессе коммуникации – создателя, автора или отправителя и получателя. PDF является преемником формата PostScript и стандартизирован как ISO 32000-2: 2017.

Обработка PDF-документов

Для Linux доступны мощные инструменты командной строки, такие как pdftk и pdfgrep. Как разработчик, с огромным энтузиазмом создает собственное программное обеспечение, основанное на Python и использующее библиотеки PDF, которые находятся в свободном доступе.

Эта статья – начало небольшой серии, в которой будут рассмотрены эти полезные библиотеки Python. В ней мы сосредоточимся на работе с существующими PDF-файлами. Вы узнаете, как читать и извлекать содержимое (как текст, так и изображения), вращать отдельные страницы и разбивать документы на отдельные страницы.

Инструменты и библиотеки

Спектр доступных решений для инструментов, модулей и библиотек PDF, связанных с Python, немного сбивает с толку, и нужно время, чтобы понять, что есть что и какие проекты поддерживаются постоянно. На основании нашего исследования актуальны следующие кандидаты:

  • PyPDF2: библиотека Python для извлечения информации и содержимого документа, разделения документов по страницам, объединения документов, обрезки страниц и добавления водяных знаков. PyPDF2 поддерживает как незашифрованные, так и зашифрованные документы.
  • PDFMiner: полностью написан на Python и хорошо работает с Python 2.4. Для Python 3 используйте клонированный пакет PDFMiner.six. Оба пакета позволяют анализировать и конвертировать PDF-документы. Это включает поддержку PDF 1.7, а также языков CJK (китайский, японский и корейский) и различных типов шрифтов (Type1, TrueType, Type3 и CID).
  • PDFQuery: он описывает себя как «быструю и удобную библиотеку для парсинга PDF», которая реализована как оболочка для PDFMiner, lxml и pyquery. Его цель дизайна – «надежно извлекать данные из наборов PDF-файлов с минимальным количеством кода».
  • tabula-py: это простая оболочка Python для tabula-java, которая может читать таблицы из PDF-файлов и преобразовывать их в Pandas DataFrames. Он также позволяет конвертировать файл PDF в файл CSV/TSV/JSON.
  • pdflib для Python: расширение библиотеки Poppler, которое предлагает для него привязки Python. Он позволяет анализировать и конвертировать PDF-документы. Не путать с его коммерческим кулоном с таким же названием.
  • PyFPDF: библиотека для создания PDF-документов на Python. Портировано из библиотеки FPDF PHP, хорошо известного замены расширения PDFlib с множеством примеров, скриптов и производных.
  • PDFTables: коммерческий сервис, предлагающий извлечение из таблиц в виде PDF-документа. Предлагает API, позволяющий использовать PDFTables, как SAAS.
  • PyX – графический пакет Python: PyX – это пакет Python для создания файлов PostScript, PDF и SVG. Он сочетает в себе абстракцию модели рисования PostScript с интерфейсом TeX или LaTeX. На основе этих примитивов строятся сложные задачи, такие как создание 2D- и 3D-графиков в готовом для публикации качестве.
  • ReportLab: амбициозная промышленная библиотека, в основном ориентированная на точное создание PDF-документов. Доступно бесплатно, как версия с открытым исходным кодом, а также как коммерческая расширенная версия под названием ReportLab PLUS.
  • PyMuPDF (также известный как «fitz»): привязки Python для MuPDF, который представляет собой легкую программу просмотра PDF и XPS. Библиотека может получить доступ к файлам в форматах PDF, XPS, OpenXPS, epub, и она известна своей высочайшей производительностью и высоким качеством рендеринга.
  • pdfrw: синтаксический анализатор PDF на чистом Python для чтения и записи PDF. Он точно воспроизводит векторные форматы без растеризации. В сочетании с ReportLab он помогает повторно использовать части существующих PDF-файлов в новых PDF-файлах, созданных с помощью ReportLab.
Библиотека Используется для
PyPDF2 Чтение
PyMuPDF Чтение
pdflib Чтение
PDFТаблицы Чтение
tabula-py Чтение
PDFMiner.six Чтение
PDFQuery Чтение
pdfrw Чтение, письмо и творчество
Reportlab Написание и создание
PyX Написание и создание
PyFPDF Написание и создание

Ниже мы сосредоточимся на PyPDF2 и PyMuPDF и объясним, как извлекать текст и изображения наиболее простым способом. Чтобы понять использование PyPDF2, помогли сочетание официальной документации и множества примеров, доступных из других ресурсов. Напротив, официальная документация PyMuPDF намного яснее и значительно быстрее при использовании библиотеки.

Извлечение текста с помощью PyPDF2

PyPDF2 можно установить как обычный программный пакет или с помощью pip3 (для Python3). Тесты здесь основаны на пакете для предстоящего выпуска Debian GNU или Linux 10 «Buster». Имя пакета Debian – python3-pypdf2.

В примере 1 сначала импортируется класс PdfFileReader. Затем, используя этот класс, он открывает документ и извлекает информацию о документе с помощью метода getDocumentInfo(), количество страниц с помощью getDocumentInfo() и содержимое первой страницы.

Обратите внимание, что PyPDF2 начинает подсчет страниц с 0, и поэтому вызов pdf.getPage (0) возвращает первую страницу документа. В конце концов, извлеченная информация выводится на стандартный вывод.

Пример 1:

#!/usr/bin/python

from PyPDF2 import PdfFileReader

pdf_document = "example.pdf"
with open(pdf_document, "rb") as filehandle:
    pdf = PdfFileReader(filehandle)
    info = pdf.getDocumentInfo()
    pages = pdf.getNumPages()

    print (info)
    print ("number of pages: %i" % pages)

    page1 = pdf.getPage(0)
    print(page1)
    print(page1.extractText())

Извлечение информации и содержимого документа

Как показано на рисунке 1 выше, извлеченный текст печатается на постоянной основе. Здесь нет абзацев или разделений предложений. Как указано в документации PyPDF2, все текстовые данные возвращаются в том порядке, в котором они предоставлены в потоке содержимого страницы, и их использование может привести к некоторым сюрпризам. Это в основном зависит от внутренней структуры документа PDF и от того, как поток инструкций PDF был создан процессом записи PDF.

С помощью PyMuPDF

PyMuPDF доступен на веб-сайте PyPi, и вы устанавливаете пакет с помощью следующей команды в терминале:

$ pip3 install PyMuPDF

Отображение информации о документе, печать количества страниц и извлечение текста из PDF-документа выполняется аналогично PyPDF2 (см. пример 2). Импортируемый модуль называется fitz и восходит к предыдущему имени PyMuPDF.

Пример 2:

#!/usr/bin/python

import fitz

pdf_document = "example.pdf"
doc = fitz.open(pdf_document):
print ("number of pages: %i" % doc.pageCount)
print(doc.metadata)

page1 = doc.loadPage(0)
page1text = page1.getText("text")
print(page1text)

Преимущество PyMuPDF заключается в том, что он сохраняет неизменной исходную структуру документа – целые абзацы с разрывами строк сохраняются, как и в документе PDF .

Извлеченные текстовые данные

С помощью PyMuPDF

PyMuPDF упрощает извлечение изображений из документов PDF с помощью метода getPageImageList(). Пример 3 основан на примере вики-страницы PyMuPDF и извлекает и сохраняет все изображения из PDF-файла в виде файлов PNG на постраничной основе. Если изображение имеет цветовое пространство CMYK, оно сначала будет преобразовано в RGB.

Пример 3:

#!/usr/bin/python

import fitz

pdf_document = fitz.open("file.pdf")
for current_page in range(len(pdf_document)):
    for image in pdf_document.getPageImageList(current_page):
        xref = image[0]
        pix = fitz.Pixmap(pdf_document, xref)
        if pix.n < 5:        # this is GRAY or RGB
            pix.writePNG("page%s-%s.png" % (current_page, xref))
        else:                # CMYK: convert to RGB first
            pix1 = fitz.Pixmap(fitz.csRGB, pix)
            pix1.writePNG("page%s-%s.png" % (current_page, xref))
            pix1 = None
        pix = None

Запустив этот скрипт Python на 400-страничном PDF-файле, он извлек 117 изображений менее чем за 3 секунды, что удивительно. Отдельные изображения хранятся в формате PNG. Чтобы сохранить исходный формат и размер изображения, вместо преобразования в PNG ознакомьтесь с расширенными версиями скриптов в вики PyMuPDF.

Извлеченные изображения

Разделение PDF-файлов на страницы с помощью PyPDF2

В этом примере сначала необходимо импортировать классы PdfFileReader и PdfFileWriter. Затем мы открываем PDF-файл, создаем объект-читатель и просматриваем все страницы в цикле, используя метод getNumPages объекта-читателя.

Внутри цикла for мы создаем новый экземпляр PdfFileWriter, который пока не содержит никаких страниц. Затем мы добавляем текущую страницу к нашему объекту записи, используя метод pdfWriter.addPage(). Этот метод принимает объект страницы, который мы получаем с помощью метода PdfFileReader.getPage().

Следующим шагом является создание уникального имени файла, что мы делаем, используя исходное имя файла плюс слово «страница» плюс номер страницы. Мы добавляем 1 к текущему номеру страницы, потому что PyPDF2 считает номера страниц, начиная с нуля.

Наконец, мы открываем новое имя файла в режиме «двоичной записи» (режим wb) и используем метод write() класса pdfWriter для сохранения извлеченной страницы на диск.

Пример 4:

#!/usr/bin/python

from PyPDF2 import PdfFileReader, PdfFileWriter

pdf_document = "example.pdf"
pdf = PdfFileReader(pdf_document)

for page in range(pdf.getNumPages()):
    pdf_writer = PdfFileWriter
    current_page = pdf.getPage(page)
    pdf_writer.addPage(current_page)

    outputFilename = "example-page-{}.pdf".format(page + 1)
    with open(outputFilename, "wb") as out:
        pdf_writer.write(out)

        print("created", outputFilename)

Разбиение PDF-файла

Найти все страницы, содержащие текст

Этот вариант использования весьма практичен и работает аналогично pdfgrep. Используя PyMuPDF, скрипт возвращает все номера страниц, которые содержат заданную строку поиска. Страницы загружаются одна за другой, и с помощью метода searchFor() обнаруживаются все вхождения строки поиска. В случае совпадения соответствующее сообщение выводится на стандартный вывод.

Листинг 5:

#!/usr/bin/python

import fitz

filename = "example.pdf"
search_term = "invoice"
pdf_document = fitz.open(filename):

for current_page in range(len(pdf_document)):
    page = pdf_document.loadPage(current_page)
    if page.searchFor(search_term):
        print("%s found on page %i" % (search_term, current_page))

На рисунке 5 ниже показан результат поиска по запросу «Debian GNU или Linux» в 400-страничной книге.

 Разбиение PDF-файла

Заключение

Показанные здесь методы довольно мощные. Благодаря сравнительно небольшому количеству строк кода легко получить результат.

Оставить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

This div height required for enabling the sticky sidebar