Как работать с PDF в Python

Как работать с PDF в Python

Portable Document Format или PDF - это формат файла, который можно использовать для надежного представления и обмена документами в операционных системах. Первоначально PDF был изобретен Adobe, но теперь этоopen standard, поддерживаемое Международной организацией по стандартизации (ISO). Вы можете работать с уже существующим PDF-файлом в Python, используя пакетPyPDF2.

PyPDF2 - это пакетpure-Python, который можно использовать для многих различных типов операций с PDF.

К концу этой статьи вы будете знать, как делать следующее:

  • Извлечение информации о документе из PDF в Python

  • Поворот страниц

  • Объединить PDF-файлы

  • Разделить PDF-файлы

  • Добавить водяные знаки

  • Зашифровать PDF

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

Free Bonus:Click here to get access to a chapter from Python Tricks: The Book, который демонстрирует вам лучшие практики Python на простых примерах, которые вы можете мгновенно применить для написания более красивого кода Pythonic.

ИсторияpyPdf,PyPDF2 иPyPDF4

Исходный пакетpyPdf был выпущен еще в 2005 году. Последний официальный выпускpyPdf был в 2010 году. Примерно через год компания под названиемPhasit спонсировала форкpyPdf под названиемPyPDF2. Код был написан для обратной совместимости с оригиналом и работал довольно хорошо в течение нескольких лет, а последний выпуск был в 2016 году.

Была краткая серия выпусков пакета под названиемPyPDF3, а затем проект был переименован вPyPDF4. Все эти проекты делают примерно одно и то же, но самая большая разница междуpyPdf и PyPDF2 + заключается в том, что в последних версиях добавлена ​​поддержка Python 3. Существует другой форк Python 3 от исходногоpyPdf for Python 3, но он не поддерживался в течение многих лет.

Хотя отPyPDF2 недавно отказались, новыйPyPDF4 не имеет полной обратной совместимости сPyPDF2. Большинство примеров в этой статье будут отлично работать сPyPDF4, но есть некоторые, которые не могут, поэтомуPyPDF4 не рассматривается более подробно в этой статье. Не стесняйтесь заменять импортPyPDF2 наPyPDF4 и посмотреть, как это сработает для вас.

pdfrw: альтернатива

Патрик Мопин создал пакет под названиемpdfrw, который может делать многие из тех же вещей, что иPyPDF2. Вы можете использоватьpdfrw для всех видов задач, которые вы узнаете из этой статьи дляPyPDF2, за заметным исключением шифрования.

Самая большая разница, когда дело доходит доpdfrw, заключается в том, что он интегрируется с пакетомReportLab, поэтому вы можете взять уже существующий PDF-файл и создать новый с помощью ReportLab, используя часть или весь уже существующий PDF-файл.

Монтаж

УстановитьPyPDF2 можно с помощьюpip илиconda, если вы используете Anaconda вместо обычного Python.

Вот как бы вы установилиPyPDF2 сpip:

$ pip install pypdf2

Установка выполняется довольно быстро, посколькуPyPDF2 не имеет зависимостей. Скорее всего, вы потратите столько же времени на скачивание пакета, сколько и его установки.

Теперь давайте продолжим и узнаем, как извлечь некоторую информацию из PDF.

Как извлечь информацию о документе из PDF в Python

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

Вот текущие типы данных, которые могут быть извлечены:

  • автор

  • творец

  • Режиссер

  • Предмет

  • заглавие

  • Количество страниц

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

Давайте напишем некоторый код с использованием этого PDF и узнаем, как вы можете получить доступ к этим атрибутам:

# extract_doc_info.py

from PyPDF2 import PdfFileReader

def extract_information(pdf_path):
    with open(pdf_path, 'rb') as f:
        pdf = PdfFileReader(f)
        information = pdf.getDocumentInfo()
        number_of_pages = pdf.getNumPages()

    txt = f"""
    Information about {pdf_path}:

    Author: {information.author}
    Creator: {information.creator}
    Producer: {information.producer}
    Subject: {information.subject}
    Title: {information.title}
    Number of pages: {number_of_pages}
    """

    print(txt)
    return information

if __name__ == '__main__':
    path = 'reportlab-sample.pdf'
    extract_information(path)

Здесь вы импортируетеPdfFileReader из пакетаPyPDF2. PdfFileReader - это класс с несколькими методами для взаимодействия с файлами PDF. В этом примере вы вызываете.getDocumentInfo(), который вернет экземплярDocumentInformation. Он содержит большую часть интересующей вас информации. Вы также вызываете.getNumPages() для объекта чтения, который возвращает количество страниц в документе.

Note: Этот последний блок кода использует новые f-строки Python 3 для форматирования строк. Если вы хотите узнать больше, можете посмотретьPython 3’s f-Strings: An Improved String Formatting Syntax (Guide).

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

ХотяPyPDF2 имеет.extractText(), который можно использовать на его объектах страницы (не показаны в этом примере), он работает не очень хорошо. Некоторые PDF-файлы возвращают текст, а некоторые возвращают пустую строку. Если вы хотите извлечь текст из PDF-файла, вам следует вместо этого проверить проектPDFMiner. PDFMiner намного надежнее и был специально разработан для извлечения текста из PDF-файлов.

Теперь вы готовы узнать о вращении страниц PDF.

Как вращать страницы

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

В этом примере вы можете выбрать Real Pythonarticle и распечатать его в формате PDF.

Давайте узнаем, как повернуть несколько страниц этой статьи с помощьюPyPDF2:

# rotate_pages.py

from PyPDF2 import PdfFileReader, PdfFileWriter

def rotate_pages(pdf_path):
    pdf_writer = PdfFileWriter()
    pdf_reader = PdfFileReader(path)
    # Rotate page 90 degrees to the right
    page_1 = pdf_reader.getPage(0).rotateClockwise(90)
    pdf_writer.addPage(page_1)
    # Rotate page 90 degrees to the left
    page_2 = pdf_reader.getPage(1).rotateCounterClockwise(90)
    pdf_writer.addPage(page_2)
    # Add a page in normal orientation
    pdf_writer.addPage(pdf_reader.getPage(2))

    with open('rotate_pages.pdf', 'wb') as fh:
        pdf_writer.write(fh)

if __name__ == '__main__':
    path = 'Jupyter_Notebook_An_Introduction.pdf'
    rotate_pages(path)

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

Затем вы можете использовать.GetPage(), чтобы получить желаемую страницу. Здесь вы берете нулевую страницу, которая является первой страницей. Затем вы вызываете метод.rotateClockwise() объекта страницы и переходите под углом 90 градусов. Затем для второй страницы вы вызываете.rotateCounterClockwise() и также передаете его на 90 градусов.

Note: ПакетPyPDF2 позволяет вам поворачивать страницу только с шагом 90 градусов. В противном случае вы получитеAssertionError.

После каждого вызова методов вращения вы вызываете.addPage(). Это добавит повернутую версию страницы к объекту записи. Последняя страница, которую вы добавляете в объект записи, - это страница 3 без поворота.

Наконец, вы записываете новый PDF-файл, используя.write(). В качестве параметра он принимаетfile-like object. Этот новый PDF будет содержать три страницы. Первые два будут вращаться в противоположных направлениях друг от друга и будут в альбомной ориентации, в то время как третья страница является обычной страницей.

Теперь давайте узнаем, как вы можете объединить несколько PDF-файлов в один.

Как объединить PDF-файлы

Есть много ситуаций, когда вы захотите взять два или более PDF-файлов и объединить их в один PDF-файл. Например, у вас может быть стандартная титульная страница, на которую нужно перейти ко многим типам отчетов. Вы можете использовать Python, чтобы помочь вам в этом.

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

Давайте продолжим и напишем код, который вы можете использовать для объединения PDF-файлов:

# pdf_merging.py

from PyPDF2 import PdfFileReader, PdfFileWriter

def merge_pdfs(paths, output):
    pdf_writer = PdfFileWriter()

    for path in paths:
        pdf_reader = PdfFileReader(path)
        for page in range(pdf_reader.getNumPages()):
            # Add each page to the writer object
            pdf_writer.addPage(pdf_reader.getPage(page))

    # Write out the merged PDF
    with open(output, 'wb') as out:
        pdf_writer.write(out)

if __name__ == '__main__':
    paths = ['document1.pdf', 'document2.pdf']
    merge_pdfs(paths, output='merged.pdf')

Вы можете использоватьmerge_pdfs(), когда у вас есть список PDF-файлов, которые вы хотите объединить. Вам также необходимо знать, где сохранить результат, поэтому эта функция принимает список входных путей и выходной путь.

Затем вы перебираете входные данные и создаете объект для чтения PDF для каждого из них. Затем вы переберете все страницы в файле PDF и используете.addPage(), чтобы добавить каждую из этих страниц к себе.

Как только вы закончите итерацию по всем страницам всех PDF-файлов в вашем списке, вы в конце запишете результат.

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

Давайте узнаем, как сделать обратное слияние!

Как разделить PDF-файлы

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

Вот как вы можете использоватьPyPDF2 для разделения вашего PDF-файла на несколько файлов:

# pdf_splitting.py

from PyPDF2 import PdfFileReader, PdfFileWriter

def split(path, name_of_split):
    pdf = PdfFileReader(path)
    for page in range(pdf.getNumPages()):
        pdf_writer = PdfFileWriter()
        pdf_writer.addPage(pdf.getPage(page))

        output = f'{name_of_split}{page}.pdf'
        with open(output, 'wb') as output_pdf:
            pdf_writer.write(output_pdf)

if __name__ == '__main__':
    path = 'Jupyter_Notebook_An_Introduction.pdf'
    split(path, 'jupyter_page')

В этом примере вы снова создаете объект для чтения PDF и перебираете его страницы. Для каждой страницы в PDF вы создадите новый экземпляр PDF Writer и добавите к нему одну страницу. Затем вы запишите эту страницу в файл с уникальным именем. Когда скрипт завершит работу, вы должны разбить каждую страницу исходного PDF на отдельные PDF-файлы.

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

Как добавить водяные знаки

Водяные знаки обозначают изображения или рисунки на печатных и цифровых документах. Некоторые водяные знаки можно увидеть только в особых условиях освещения. Водяной знак важен потому, что он позволяет защитить вашу интеллектуальную собственность, такую ​​как изображения или PDF-файлы. Другой термин для водяного знака - наложение.

Вы можете использовать Python иPyPDF2 для водяных знаков на ваших документах. Вы должны иметь PDF, который содержит только изображение или текст водяного знака.

Давайте узнаем, как добавить водяной знак сейчас:

# pdf_watermarker.py

from PyPDF2 import PdfFileWriter, PdfFileReader

def create_watermark(input_pdf, output, watermark):
    watermark_obj = PdfFileReader(watermark)
    watermark_page = watermark_obj.getPage(0)

    pdf_reader = PdfFileReader(input_pdf)
    pdf_writer = PdfFileWriter()

    # Watermark all the pages
    for page in range(pdf_reader.getNumPages()):
        page = pdf_reader.getPage(page)
        page.mergePage(watermark_page)
        pdf_writer.addPage(page)

    with open(output, 'wb') as out:
        pdf_writer.write(out)

if __name__ == '__main__':
    create_watermark(
        input_pdf='Jupyter_Notebook_An_Introduction.pdf',
        output='watermarked_notebook.pdf',
        watermark='watermark.pdf')

create_watermark() принимает три аргумента:

  1. input_pdf: путь к файлу PDF, на который будет нанесен водяной знак

  2. output: путь, по которому вы хотите сохранить версию PDF с водяными знаками

  3. watermark: PDF-файл, содержащий изображение или текст водяного знака.

В коде вы открываете водяной знак PDF и берете только первую страницу документа, поскольку именно там должен находиться ваш водяной знак. Затем вы создаете объект для чтения PDF, используяinput_pdf и общий объектpdf_writer для записи PDF-файла с водяными знаками.

Следующим шагом является перебор страниц вinput_pdf. Здесь происходит волшебство. Вам нужно будет вызвать.mergePage() и передать емуwatermark_page. Когда вы это сделаете, он будет наложитьwatermark_page поверх текущей страницы. Затем вы добавляете эту недавно объединенную страницу в свой объектpdf_writer.

Наконец, вы записываете новый PDF-файл с водяными знаками на диск, и все готово!

Последняя тема, о которой вы узнаете, - какPyPDF2 обрабатывает шифрование.

Как зашифровать PDF

PyPDF2 в настоящее время поддерживает только добавление пароля пользователя и пароля владельца к уже существующему PDF-файлу. В PDF land пользовательский пароль в основном даст вам права администратора по сравнению с PDF и позволит вам установить права доступа к документу. С другой стороны, пароль пользователя просто позволяет открыть документ.

Насколько я могу судить,PyPDF2 фактически не позволяет вам устанавливать какие-либо разрешения для документа, даже если он позволяет вам установить пароль владельца.

Независимо от того, как вы можете добавить пароль, который также зашифрует PDF:

# pdf_encrypt.py

from PyPDF2 import PdfFileWriter, PdfFileReader

def add_encryption(input_pdf, output_pdf, password):
    pdf_writer = PdfFileWriter()
    pdf_reader = PdfFileReader(input_pdf)

    for page in range(pdf_reader.getNumPages()):
        pdf_writer.addPage(pdf_reader.getPage(page))

    pdf_writer.encrypt(user_pwd=password, owner_pwd=None,
                       use_128bit=True)

    with open(output_pdf, 'wb') as fh:
        pdf_writer.write(fh)

if __name__ == '__main__':
    add_encryption(input_pdf='reportlab-sample.pdf',
                   output_pdf='reportlab-encrypted.pdf',
                   password='twofish')

add_encryption() принимает входные и выходные пути PDF, а также пароль, который вы хотите добавить в PDF. Затем он открывает средство записи PDF и объект чтения, как и раньше. Так как вы захотите зашифровать весь входной PDF, вам нужно будет перебрать все его страницы и добавить их в программу записи.

Последним шагом является вызов.encrypt(), который принимает пароль пользователя, пароль владельца и указывает, следует ли добавлять 128-битное шифрование. По умолчанию включено 128-битное шифрование. Если вы установите его наFalse, вместо этого будет применяться 40-битное шифрование.

Для шифрования PDFNote: используется RC4 или AES (расширенный стандарт шифрования) для шифрования PDF в соответствии сpdflib.com.

Тот факт, что вы зашифровали свой PDF, не означает, что он обязательно безопасен. Есть инструменты для удаления паролей из PDF-файлов. Если вы хотите узнать больше, у Университета Карнеги-Меллона есть интересныйpaper on the topic.

Заключение

ПакетPyPDF2 весьма полезен и обычно работает довольно быстро. Вы можете использоватьPyPDF2 для автоматизации больших работ и использовать его возможности, чтобы лучше выполнять свою работу!

В этом уроке вы узнали, как сделать следующее:

  • Извлечение метаданных из PDF

  • Поворот страниц

  • Слияние и разделение PDF-файлов

  • Добавить водяные знаки

  • Добавить шифрование

Также следите за новым пакетомPyPDF4, так как он, скорее всего, скоро заменитPyPDF2. Вы также можете попробоватьpdfrw, который может делать многие из тех же вещей, что иPyPDF2.

Дальнейшее чтение

Если вы хотите больше узнать о работе с PDF-файлами в Python, вам следует воспользоваться некоторыми из следующих ресурсов для получения дополнительной информации: