Найти в Дзене

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

Оглавление

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

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

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

  • Извлечение информации о документе из PDF в Python
  • Поворот страниц
  • Объединить PDF-файлы
  • Разделить PDF-файлы
  • Добавить водяные знаки
  • Зашифровать PDF

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

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

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

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

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

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

Patrick Maupin создал пакет под названием 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 () для объекта reader, который возвращает количество страниц в документе.

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

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

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

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

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

В этом примере вы можете выбрать реальную статью на Python и распечатать ее в формате 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 градусов.

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

Наконец, вы записываете новый PDF с помощью .write (). В качестве параметра он принимает файлоподобный объект. Этот новый 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-файла. Если вам нужен вызов, вы также можете создать интерфейс командной строки для этой функции с помощью модуля Python argparse.

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

Как разделить 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. вывод: путь, по которому вы хотите сохранить версию PDF с водяным знаком
  3. водяной знак: PDF, содержащий изображение или текст водяного знака

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

Следующим шагом является перебор страниц в файле input_pdf. Здесь происходит волшебство. Вам нужно будет вызвать .mergePage () и передать ему 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-битное шифрование.

Заключение

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