Как работать с PDF-файлом на Python
Оглавление
- История pyPdf, PyPDF2 и PyPDF4
- pdfrw: Альтернатива
- Установка
- Как извлечь информацию о документе из PDF на Python
- Как повернуть страницы
- Как объединить PDF-файлы
- Как разделить PDF файлы
- Как добавить водяные знаки
- Как зашифровать PDF
- Заключение
- Дальнейшее чтение
Portable Document Format, или PDF, - это формат файлов, который можно использовать для надежного представления и обмена документами в разных операционных системах. Хотя PDF был изначально изобретен компанией Adobe, в настоящее время он является открытым стандартом, который поддерживается Международной организацией по стандартизации (ISO). Вы можете работать с уже существующим PDF в Python, используя пакет PyPDF2
.
PyPDF2
- это пакет pure-Python, который вы можете использовать для множества различных типов операций с PDF.
К концу этой статьи вы будете знать, как делать следующее:
- Извлечение информации о документе из PDF на Python
- Поворот страниц
- Слияние PDF-файлов
- Разделить PDF
- Добавлять водяные знаки
- Зашифровать PDF
Давайте начнем!
История pyPdf
, PyPDF2
и PyPDF4
Оригинальный пакет pyPdf
был выпущен в далеком 2005 году. Последний официальный релиз pyPdf
состоялся в 2010 году. После примерно годичного перерыва компания под названием Phasit спонсировала форк pyPdf
под названием PyPDF2
. Код был написан так, чтобы быть обратно совместимым с оригиналом, и работал довольно хорошо в течение нескольких лет, последний релиз состоялся в 2016 году.
Была короткая серия выпусков пакета под названием PyPDF3
, а затем проект был переименован в PyPDF4
. Все эти проекты делают практически одно и то же, но самое большое различие между pyPdf
и PyPDF2+ заключается в том, что в последних версиях добавлена поддержка Python 3. Существует форк оригинальной версии pyPdf
для Python 3, но он не поддерживается уже много лет.
В то время как PyPDF2
был заброшен в 2016 году, он был возрожден в 2022 году и в настоящее время активно поддерживается. Новый 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, который возвращает количество страниц в документе.
Примечание: В последнем блоке кода используются новые f-строки Python 3 для форматирования строк. Если вы хотите узнать больше, вы можете ознакомиться с Python's F-String for String Interpolation and Formatting.
У information
переменной есть несколько атрибутов экземпляра, которые вы можете использовать для получения остальных метаданных, которые вы хотите получить из документа. Вы распечатываете эту информацию, а также возвращаете ее для возможного использования в будущем.
Хотя у PyPDF2
есть .extractText()
, который можно использовать в его страничных объектах (в этом примере не показано), он работает не очень хорошо. Некоторые PDF-файлы возвращают текст, а некоторые - пустую строку. Если вы хотите извлечь текст из PDF, то вместо этого вам стоит обратить внимание на проект PDFMiner
. PDFMiner
гораздо более надежен и был специально разработан для извлечения текста из PDF.
Теперь вы готовы узнать, как вращать страницы PDF.
Как перевернуть страницы
Иногда вы получаете PDF-файлы, содержащие страницы, которые находятся в режиме пейзажа вместо портретного режима. А возможно, они даже перевернуты вверх ногами. Это может произойти, когда кто-то сканирует документ в PDF или отправляет по электронной почте. Вы можете распечатать документ и прочитать бумажную версию, а можете использовать возможности Python, чтобы повернуть неработающие страницы.
Для этого примера вы можете выбрать статью Real Python и распечатать ее в PDF.
Давайте научимся вращать несколько страниц этой статьи с помощью PyPDF2
:
# rotate_pages.py
from PyPDF2 import PdfFileReader, PdfFileWriter
def rotate_pages(pdf_path):
pdf_writer = PdfFileWriter()
pdf_reader = PdfFileReader(pdf_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, который вы хотите изменить. Внутри этой функции необходимо создать объект writer, который можно назвать pdf_writer
, и объект reader, который называется pdf_reader
.
Далее вы можете использовать .GetPage()
, чтобы получить нужную страницу. Здесь вы берете нулевую страницу, которая является первой. Затем вы вызываете метод .rotateClockwise()
объекта page и передаете 90 градусов. Затем для второй страницы вы вызываете метод .rotateCounterClockwise()
и также передаете ему 90 градусов.
Примечание: Пакет PyPDF2
позволяет поворачивать страницу только на 90 градусов. В противном случае вы получите AssertionError
.
После каждого вызова методов поворота вы вызываете .addPage()
. Это добавит повернутую версию страницы в объект writer. Последней страницей, которую вы добавляете в объект writer, будет страница 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 Reader. Далее вы перебираете все страницы в 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 reader и перебираете его страницы. Для каждой страницы 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()
принимает три аргумента:
input_pdf
: путь к файлу PDF, на который будет наложен водяной знакoutput
: путь, по которому нужно сохранить версию PDF с водяными знакамиwatermark
: PDF, содержащий изображение или текст водяного знака
В коде вы открываете PDF с водяным знаком и захватываете только первую страницу документа, поскольку именно на ней должен располагаться водяной знак. Затем вы создаете объект PDF Reader, используя input_pdf
, и общий объект pdf_writer
для записи PDF с водяным знаком.
Следующий шаг - итерация по страницам в input_pdf
. Вот здесь и происходит волшебство. Вам нужно будет вызвать .mergePage()
и передать ему watermark_page
. Когда вы это сделаете, он наложит watermark_page
поверх текущей страницы. Затем вы добавите эту новую объединенную страницу в ваш объект pdf_writer
.
Наконец, вы записываете новый PDF с водяными знаками на диск, и все готово!
Последняя тема, о которой вы узнаете, - это то, как PyPDF2
обрабатывает шифрование.
Как зашифровать PDF
PyPDF2
в настоящее время поддерживает только добавление пароля пользователя и пароля владельца к уже существующему PDF. В стране PDF пароль владельца, по сути, дает вам права администратора 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-битное шифрование.
Примечание: Для шифрования PDF используется RC4 или AES (Advanced Encryption Standard) согласно pdflib.com.
Если вы зашифровали свой PDF-файл, это не значит, что он обязательно защищен. Существуют инструменты для удаления паролей из PDF-файлов. Если вы хотите узнать больше, в Университете Карнеги-Меллона есть интересная статья на эту тему.
Заключение
Пакет PyPDF2
весьма полезен и обычно работает довольно быстро. Вы можете использовать PyPDF2
для автоматизации больших заданий и использовать его возможности, чтобы помочь вам лучше выполнять свою работу!
В этом уроке вы научились делать следующее:
- Извлечение метаданных из PDF
- Поворот страниц
- Слияние и разделение PDF-файлов
- Добавляйте водяные знаки
- Добавляйте шифрование
Также следите за более новым пакетом PyPDF4
, поскольку он, вероятно, скоро заменит PyPDF2
. Вы также можете ознакомиться с пакетом pdfrw
, который может делать многое из того же, что и PyPDF2
.
Дальнейшее чтение
Если вы хотите узнать больше о работе с PDF-файлами в Python, вам следует ознакомиться со следующими ресурсами:
- Веб-сайт
PyPDF2
- Страница Github для
PyPDF4
- Страница Github для
pdfrw
- Веб-сайт ReportLab
- Страница Github для
PDFMiner
- Camelot: PDF Table Extraction for Humans
- Создание и изменение PDF-файлов на Python (учебное пособие)