Как работать с 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()
принимает три аргумента:
-
input_pdf
: путь к файлу PDF, на который будет нанесен водяной знак -
output
: путь, по которому вы хотите сохранить версию PDF с водяными знаками -
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, вам следует воспользоваться некоторыми из следующих ресурсов для получения дополнительной информации: