(點選上方快速關註並設定為星標,一起學Python)
來源:Python資料科學 連結:
https://mp.weixin.qq.com/s/pSO3wVgjaHOvzXG4k8KQOw
Portable Document Format(可移植檔案格式),或者PDF是一種檔案格式,可以用於跨作業系統的呈現和檔案交換。儘管PDF最初是由Adobe發明的,但它現在是由國際標準化組織(ISO)維護的開放標準。你可以透過使用PyPDF2包在Python中處理已先存在的PDF。
PyPDF2是一個純Python包,可用於許多不同型別的PDF操作。
本文將帶你瞭解如何執行以下操作:
-
從Python中提取PDF中的檔案資訊
-
旋轉頁面
-
合併PDF
-
拆分PDF
-
新增水印
-
加密PDF
pyPdf,PyPDF2和PyPDF4的歷史
最初的pyPdf軟體包於2005年釋出。pyPdf的最後一個正式版本是在2010年。大約一年後,一家名為Phasit的公司贊助了一個名為PyPDF2的pyPdf分支。該程式碼編寫為向後與原始程式碼相容,並且用了好多年,效果一直很好,其最後一個版本是在2016年。
有一個名為PyPDF3的軟體包簡短系列版本,然後該專案被重新命名為PyPDF4。所有這些專案都完全相同,但pyPdf和PyPDF2 +之間的最大區別在於後者版本增加了Python 3支援。Python 3的原始pyPdf有一個不同的Python 3分支,但是這個分支已經多年沒有維護了。
雖然最近放棄了PyPDF2,但新的PyPDF4與PyPDF2沒有完全的向後相容性。本文中的大多數示例都可以與PyPDF4完美配合,但也有一些不能,這就是為什麼PyPDF4在本文中沒有更多的特色。隨意用PyPDF4替換PyPDF2的匯入,看看它是如何工作的。
pdfrw:一個替代的PDF操作包
Patrick Maupin建立了一個名為pdfrw的軟體包,它可以完成許多與PyPDF2相同的工作。除了加密的特殊情況外,本文後面提到PyPDF2的所有操作,pdfrw均可以實現。
pdfrw的最大區別在於它與ReportLab軟體包整合,因此你可以使用一些或所有預先存在的PDF構建一個新的PDF。
PyPDF2的安裝
如果使用Anaconda而不是常規Python,可以使用pip或conda安裝PyPDF2。以下是使用pip安裝PyPDF2的方法:
$ pip install pypdf2
由於PyPDF2沒有任何依賴,因此安裝非常快。
如何從Python中提取PDF檔案資訊
我們可以使用PyPDF2從PDF中提取元資料和一些文字,尤其是當在預先存在的PDF檔案上執行某些型別的自動化時是非常有用的。
以下是當前可以提取的資料型別:
- Author
- Creator
- Producer
- Subject
- Title
- Number of page
可以在自己的電腦上隨便找一個PDF檔案進行嘗試操作。下麵是使用該PDF編寫一些程式碼,並瞭解如何訪問這些屬性:
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 = 'xxxx.pdf'
extract_information(path)
首先從PyPDF2包匯入PdfFileReader。PdfFileReader是一個具有多種與PDF檔案互動的方法的類。在此示例中,我們呼叫了.getDocumentInfo(),它將傳回DocumentInformation的實體,包含了我們感興趣的大部分資訊。我們還可以在reader物件上呼叫.getNumPages(),讓它傳迴檔案中的頁數。
information這個變數具有多個實體屬性,可以使用這些屬性從檔案中獲取所需的其餘元資料。我們可以打印出該資訊並將其傳回以備將來使用。
雖然PyPDF2具有.extractText(),可以在其頁面物件上使用提取文字(本例中未顯示),但它的效果不是很好。有些PDF會傳迴文字,有些會傳回空字串。如果要從PDF中提取文字,建議應該看一下PDFMiner專案。PDFMiner更加強大,專門用於從PDF中提取文字。
如何旋轉頁面?
有時候PDF是橫向樣式而不是縱向樣式,甚至是顛倒的。當有人掃描檔案為PDF或電子郵件時,很可能會發生這種情況。我們可以打印出檔案並閱讀紙質版本,也可以使用Python的強大功能來旋轉有問題的頁面。
下麵看一下如何使用PyPDF2旋轉文章的一些頁面:
from PyPDF2 import PdfFileReader, PdfFileWriter
def rotate_pages(pdf_path):
pdf_writer = PdfFileWriter()
pdf_reader = PdfFileReader(path)
# 順時針旋轉90度
page_1 = pdf_reader.getPage(0).rotateClockwise(90)
pdf_writer.addPage(page_1)
# 逆時針旋轉90度
page_2 = pdf_reader.getPage(1).rotateCounterClockwise(90)
pdf_writer.addPage(page_2)
# 在正常方向上新增一頁
pdf_writer.addPage(pdf_reader.getPage(2))
with open('rotate_pages.pdf', 'wb') as fh:
pdf_writer.write(fh)
if __name__ == '__main__':
path = '新路徑.pdf'
rotate_pages(path)
上面除了pdfileReader之外,還匯入了pdfileWriter,因為我們需要編寫一個新的pdf。rotate_pages()獲取要修改的PDF的路徑。在這個函式中,需要建立一個可以命名為pdf-writer的writer物件和一個名為pdf-reader的reader物件。
接下來,可以使用.get page()獲取所需的頁面。上面開始輸入了第0頁,也就是第一頁,呼叫page物件的.rotateClockwise()順時針旋轉方法並輸入90。然後同樣地,對於第二頁,呼叫.rotateCounterLockwise()逆時針旋轉並輸入90。
每次呼叫Rotation旋轉方法後,都會呼叫.addPage(),這將向writer物件新增頁面的旋轉版本。最後一頁是第3頁,沒有對其進行任何旋轉。最後,使用.write()把所有新頁寫入新的PDF。
如何合併PDF?
在許多情況下,我們希望將兩個或多個PDF合併到一個PDF中。例如,現在可能有一個標準的封面,需要轉到許多型別的報告中。這時候就可以使用python來幫助完成這類工作。
下麵是實現的程式碼,完成PDF合併的操作:
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()):
# 將每頁新增到writer物件
pdf_writer.addPage(pdf_reader.getPage(page))
# 寫入合併的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')
假如有一個要合併到一起的pdf串列時,可以直接使用merge_pdf函式完成。此函式採用了輸入路徑和輸出路徑作為引數。
首先遍歷輸入的paths,併為每個輸入建立一個PDF閱讀物件。然後遍歷PDF檔案中的所有頁面,並使用.addpage()將這些頁面寫入writer物件。當完成對串列中所有PDF的所有頁面的寫入後,將在末尾寫入新的結果中。
如果不想合併每個PDF的所有頁面,可以透過新增一系列要新增的頁面來稍微增強這個指令碼。挑戰一點的話,也可以使用Python的argparse模組為這個函式建立一個命令列介面。
如何拆分PDF?
有時可能需要將PDF拆分為多個PDF,對於包含大量掃描內容的PDF來說尤其重要。以下是如何使用PyPDF2將PDF拆分為多個檔案:
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 = 'xxx.pdf'
split(path, 'jupyter_page')
這個函式中再次建立了PDF的reaer物件,並對其所讀取的頁面進行遍歷。對於PDF中的每個頁面,建立一個新的PDF的writer實體並向其新增單個頁面。然後,將該頁面寫入一個唯一命名的檔案。指令碼執行完畢後,就可以將原始PDF的每個頁面拆分為單獨的PDF。
如何新增水印?
水印是紙質或者電子檔案上的影象或圖案,一些水印只能在特殊照明條件下才能看到。水印的重要性在於它可以保護你的智慧財產權,例如影象或PDF。
我們可以使用Python和PyPDF2為檔案新增水印,而且是擁有僅包含水印影象或文字的PDF。下麵是向PDF新增水印方法:
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()
# 給所有頁面新增水印
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並從檔案中抓取第一頁,因為這是水印應該駐留的位置。然後使用input_pdf和通用pdf_writer物件建立PDF的writer物件,以寫出帶水印的PDF。
下一步是遍歷input_pdf中的頁面,然後呼叫.mergePage()並以用上面讀取的水印物件watermark_page為引數,這樣會將watermark_page改寫在當前頁面的頂部,然後再將新合併的頁面新增到pdf_writer物件中。遍歷完成後,最後將新加水印的PDF寫入磁碟。
如何加密PDF?
PyPDF2目前僅支援將使用者密碼和所有者密碼新增到預先存在的PDF。在PDF版本中,所有者密碼會提供PDF的管理員許可權,並允許設定檔案的許可權,而使用者密碼只允許開啟檔案。
實際上,PyPDF2是不允許設定檔案的任何許可權的,即使它允許設定所有者密碼的情況下。但無論如何,這是可以加密的方式,也將固有地加密PDF:
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,因此需要遍歷其所有頁面並將其新增到writer編寫器。最後一步是呼叫.encrypt(),以使用者密碼,所有者密碼以及是否應該新增128位加密為引數。預設情況下,要啟用128位加密。如果將其設定為False,則將應用40位加密。
結論
PyPDF2包非常有用,可以使用PyPDF2自動執行指令碼完成PDF檔案的批次操作。本文介紹瞭如何從PDF中提取元資料,旋轉頁面,合併和拆分PDF,新增水印,以及新增加密的操作。
同時,還要關註較新的PyPDF4包,因為它很快就會取代PyPDF2。也可以看看pdfrw包,它也可以執行許多與PyPDF2相同的操作。
朋友會在“發現-看一看”看到你“在看”的內容