您好,登錄后才能下訂單哦!
本文小編為大家詳細介紹“Python辦公自動化之PDF的操作方法有哪些”,內容詳細,步驟清晰,細節處理妥當,希望這篇“Python辦公自動化之PDF的操作方法有哪些”文章能幫助大家解決疑惑,下面跟著小編的思路慢慢深入,一起來學習新知識吧。
Python 操作 PDF 會用到兩個庫,分別是:PyPDF2 和 pdfplumber。
其中 PyPDF2 可以更好的讀取、寫入、分割、合并PDF文件,而 pdfplumber 可以更好的讀取 PDF 文件中內容和提取 PDF 中的表格。
由于這兩個庫都不是 Python 的標準庫,所以在使用之前都需要單獨安裝。
win+r 后輸入 cmd 打開 command 窗口,依次輸入如下命令進行安裝:
pip install PyPDF2
pip install pdfplumber
安裝完成后顯示 success 則表示安裝成功。
將一個完整的 PDF 拆分成幾個小的 PDF,因為主要涉及到 PDF 整體的操作,所以本小節需要用到 PyPDF2 這個庫。
拆分的大概思路如下:
讀取 PDF 的整體信息、總頁數等
遍歷每一頁內容,以每個 step 為間隔將 PDF 存成每一個小的文件塊
將小的文件塊重新保存為新的 PDF 文件
需要注意的是,在拆分的過程中,可以手動設置間隔,例如:每5頁保存成一個小的 PDF 文件。
拆分的代碼如下:
import os from PyPDF2 import PdfFileWriter, PdfFileReader def split_pdf(filename, filepath, save_dirpath, step=5): """ 拆分PDF為多個小的PDF文件, @param filename:文件名 @param filepath:文件路徑 @param save_dirpath:保存小的PDF的文件路徑 @param step: 每step間隔的頁面生成一個文件,例如step=5,表示0-4頁、5-9頁...為一個文件 @return: """ if not os.path.exists(save_dirpath): os.mkdir(save_dirpath) pdf_reader = PdfFileReader(filepath) # 讀取每一頁的數據 pages = pdf_reader.getNumPages() for page in range(0, pages, step): pdf_writer = PdfFileWriter() # 拆分pdf,每 step 頁的拆分為一個文件 for index in range(page, page+step): if index < pages: pdf_writer.addPage(pdf_reader.getPage(index)) # 保存拆分后的小文件 save_path = os.path.join(save_dirpath, filename+str(int(page/step)+1)+'.pdf') print(save_path) with open(save_path, "wb") as out: pdf_writer.write(out) print("文件已成功拆分,保存路徑為:"+save_dirpath) split_pdf(filename, filepath, save_dirpath, step=5)
以“易方達中小盤混合型證券投資基金2020年中期報告”為例,整個 PDF 文件一共 46 頁,每5頁為間隔,最終生成了10個小的 PDF 文件。
比起拆分來,合并的思路更加簡單:
確定要合并的 文件順序
循環追加到一個文件塊中
保存成一個新的文件
對應的代碼比較簡單:
import os from PyPDF2 import PdfFileReader, PdfFileWriter def concat_pdf(filename, read_dirpath, save_filepath): """ 合并多個PDF文件 @param filename:文件名 @param read_dirpath:要合并的PDF目錄 @param save_filepath:合并后的PDF文件路徑 @return: """ pdf_writer = PdfFileWriter() # 對文件名進行排序 list_filename = os.listdir(read_dirpath) list_filename.sort(key=lambda x: int(x[:-4].replace(filename, ""))) for filename in list_filename: print(filename) filepath = os.path.join(read_dirpath, filename) # 讀取文件并獲取文件的頁數 pdf_reader = PdfFileReader(filepath) pages = pdf_reader.getNumPages() # 逐頁添加 for page in range(pages): pdf_writer.addPage(pdf_reader.getPage(page)) # 保存合并后的文件 with open(save_filepath, "wb") as out: pdf_writer.write(out) print("文件已成功合并,保存路徑為:"+save_filepath) concat_pdf(filename, read_dirpath, save_filepath)
涉及到具體的 PDF 內容 操作,本小節需要用到 pdfplumber 這個庫。
在進行文字提取的時候,主要用到 extract_text 這個函數。
具體代碼如下:
import os import pdfplumber def extract_text_info(filepath): """ 提取PDF中的文字 @param filepath:文件路徑 @return: """ with pdfplumber.open(filepath) as pdf: # 獲取第2頁數據 page = pdf.pages[1] print(page.extract_text()) # 提取文字內容 extract_text_info(filepath)
可以看到,直接通過下標即可定位到相應的頁碼,從而通過 extract_text 函數提取該也的所有文字。
而如果想要提取所有頁的文字,只需要改成:
with pdfplumber.open(filepath) as pdf: # 獲取全部數據 for page in pdf.pages print(page.extract_text())
例如,提取“易方達中小盤混合型證券投資基金2020年中期報告” 第一頁的內容時,源文件是這樣的:
運行代碼后提取出來是這樣的:
同樣的,本節是對具體內容的操作,所以也需要用到 pdfplumber 這個庫。
和提取文字十分類似的是,提取表格內容只是將 extract_text 函數換成了 extract_table 函數。
對應的代碼如下:
import os import pandas as pd import pdfplumber def extract_table_info(filepath): """ 提取PDF中的圖表數據 @param filepath: @return: """ with pdfplumber.open(filepath) as pdf: # 獲取第18頁數據 page = pdf.pages[17] # 如果一頁有一個表格,設置表格的第一行為表頭,其余為數據 table_info = page.extract_table() df_table = pd.DataFrame(table_info[1:], columns=table_info[0]) df_table.to_csv('dmeo.csv', index=False, encoding='gbk') # 提取表格內容 extract_table_info(filepath)
上面代碼可以獲取到第 18 頁的第一個表格內容,并且將其保存為 csv 文件存在本地。
但是,如果說第 18 頁有多個表格內容呢?
因為讀取的表格會被存成二維數組,而多個二維數組就組成一個三維數組。
遍歷這個三位數組,就可以得到該頁的每一個表格數據,對應的將 extract_table 函數 改成 extract_tables 即可。
具體代碼如下:
# 如果一頁有多個表格,對應的數據是一個三維數組 tables_info = page.extract_tables() for index in range(len(tables_info)): # 設置表格的第一行為表頭,其余為數據 df_table = pd.DataFrame(tables_info[index][1:], columns=tables_info[index][0]) print(df_table) # df_table.to_csv('dmeo.csv', index=False, encoding='gbk')
以“易方達中小盤混合型證券投資基金2020年中期報告” 第 xx 頁的第一個表格為例:
源文件中的表格是這樣的:
提取并存入 excel 之后的表格是這樣的:
提取 PDF 中的圖片和將 PDF 轉存為圖片是不一樣的(下一小節),需要區分開。
提取圖片:顧名思義,就是將內容中的圖片都提取出來;
轉存為圖片:則是將每一頁的 PDF 內容存成一頁一頁的圖片,下一小節會詳細說明
轉存為圖片中,需要用到一個模塊叫 fitz,fitz 的最新版 1.18.13,非最新版的在部分函數名稱上存在差異,代碼中會標記出來
使用 fitz 需要先安裝 PyMuPDF 模塊,安裝方式如下:
pip install PyMuPDF
提取圖片的整體邏輯如下:
使用 fitz 打開文檔,獲取文檔詳細數據
遍歷每一個元素,通過正則找到圖片的索引位置
使用 Pixmap 將索引對應的元素生成圖片
通過 size 函數過濾較小的圖片
實現的具體代碼如下:
import os import re import fitz def extract_pic_info(filepath, pic_dirpath): """ 提取PDF中的圖片 @param filepath:pdf文件路徑 @param pic_dirpath:要保存的圖片目錄路徑 @return: """ if not os.path.exists(pic_dirpath): os.makedirs(pic_dirpath) # 使用正則表達式來查找圖片 check_XObject = r"/Type(?= */XObject)" check_Image = r"/Subtype(?= */Image)" img_count = 0 """1. 打開pdf,打印相關信息""" pdf_info = fitz.open(filepath) # 1.16.8版本用法 xref_len = doc._getXrefLength() # 最新版本 xref_len = pdf_info.xref_length() # 打印PDF的信息 print("文件名:{}, 頁數: {}, 對象: {}".format(filepath, len(pdf_info), xref_len-1)) """2. 遍歷PDF中的對象,遇到是圖像才進行下一步,不然就continue""" for index in range(1, xref_len): # 1.16.8版本用法 text = doc._getXrefString(index) # 最新版本 text = pdf_info.xref_object(index) is_XObject = re.search(check_XObject, text) is_Image = re.search(check_Image, text) # 如果不是對象也不是圖片,則不操作 if is_XObject or is_Image: img_count += 1 # 根據索引生成圖像 pix = fitz.Pixmap(pdf_info, index) pic_filepath = os.path.join(pic_dirpath, 'img_' + str(img_count) + '.png') """pix.size 可以反映像素多少,簡單的色素塊該值較低,可以通過設置一個閾值過濾。以閾值 10000 為例過濾""" # if pix.size < 10000: # continue """三、 將圖像存為png格式""" if pix.n >= 5: # 先轉換CMYK pix = fitz.Pixmap(fitz.csRGB, pix) # 存為PNG pix.writePNG(pic_filepath) # 提取圖片內容 extract_pic_info(filepath, pic_dirpath)
以本節示例的“易方達中小盤混合型證券投資基金2020年中期報告” 中的圖片為例,代碼運行后提取的圖片如下:
這個結果和文檔中的共 1 張圖片的結果符合。
轉換為照片比較簡單,就是將一頁頁的 PDF 轉換為一張張的圖片。大致過程如下:
首先需要安裝對應的庫,最新的 pdf2image 庫版本應該是 1.14.0。
安裝方式如下:
pip install pdf2image
對于不同的平臺,需要安裝相應的組件,這里以 windows 平臺和 mac 平臺為例:
Windows 平臺
對于 windows 用戶需要安裝 poppler for Windows
另外,還需要添加環境變量, 將 bin 文件夾的路徑添加到環境變量 PATH 中。
注意這里配置之后需要重啟一下電腦才會生效,不然會報錯
Mac
對于 mac 用戶,需要安裝 poppler for Mac,詳細代碼如下:
import os from pdf2image import convert_from_path, convert_from_bytes def convert_to_pic(filepath, pic_dirpath): """ 每一頁的PDF轉換成圖片 @param filepath:pdf文件路徑 @param pic_dirpath:圖片目錄路徑 @return: """ print(filepath) if not os.path.exists(pic_dirpath): os.makedirs(pic_dirpath) images = convert_from_bytes(open(filepath, 'rb').read()) # images = convert_from_path(filepath, dpi=200) for image in images: # 保存圖片 pic_filepath = os.path.join(pic_dirpath, 'img_'+str(images.index(image))+'.png') image.save(pic_filepath, 'PNG') # PDF轉換為圖片 convert_to_pic(filepath, pic_dirpath)
以本節示例的“易方達中小盤混合型證券投資基金2020年中期報告” 中的圖片為例,該文檔共 46 頁,保存后的 PDF 照片如下:
一共 46 張圖片
添加水印后的效果如下:
在制作水印的時候,可以自定義水印內容、透明度、斜度、字間寬度等等,可操作性比較好。
前面專門寫過一篇文章,講的特別詳細:Python快速給PDF文件添加自定義水印。
你可能在打開部分 PDF 文件的時候,會彈出下面這個界面:
這種就是 PDF 文件被加密了,在打開的時候需要相應的密碼才行。
本節所提到的也只是基于 PDF 文檔的加密解密,而不是所謂的 PDF 密碼破解。
在對 PDF 文件加密需要使用 encrypt 函數,對應的加密代碼也比較簡單:
import os from PyPDF2 import PdfFileReader, PdfFileWriter def encrypt_pdf(filepath, save_filepath, passwd='xiaoyi'): """ PDF文檔加密 @param filepath:PDF文件路徑 @param save_filepath:加密后的文件保存路徑 @param passwd:密碼 @return: """ pdf_reader = PdfFileReader(filepath) pdf_writer = PdfFileWriter() for page_index in range(pdf_reader.getNumPages()): pdf_writer.addPage(pdf_reader.getPage(page_index)) # 添加密碼 pdf_writer.encrypt(passwd) with open(save_filepath, "wb") as out: pdf_writer.write(out) # 文檔加密 encrypt_pdf(filepath, save_filepath, passwd='xiaoyi')
代碼執行成功后再次打開 PDF 文件則需要輸入密碼才行。
根據這個思路,破解 PDF 也可以通過暴力求解實現,例如:通過本地密碼本一個個去嘗試,或者根據數字+字母的密碼形式循環嘗試,最終成功打開的密碼就是破解密碼。
上述破解方法耗時耗力,不建議嘗試
另外,針對已經加密的 PDF 文件,也可以使用 decrypt 函數進行解密操作。
解密代碼如下:
def decrypt_pdf(filepath, save_filepath, passwd='xiaoyi'): """ 解密 PDF 文檔并且保存為未加密的 PDF @param filepath:PDF文件路徑 @param save_filepath:解密后的文件保存路徑 @param passwd:密碼 @return: """ pdf_reader = PdfFileReader(filepath) # PDF文檔解密 pdf_reader.decrypt('xiaoyi') pdf_writer = PdfFileWriter() for page_index in range(pdf_reader.getNumPages()): pdf_writer.addPage(pdf_reader.getPage(page_index)) with open(save_filepath, "wb") as out: pdf_writer.write(out) # 文檔解密 decrypt_pdf(filepath, save_filepath, passwd='xiaoyi')
解密完成后的 PDF 文檔打開后不再需要輸入密碼,如需加密可再次執行加密代碼。
讀到這里,這篇“Python辦公自動化之PDF的操作方法有哪些”文章已經介紹完畢,想要掌握這篇文章的知識點還需要大家自己動手實踐使用過才能領會,如果想了解更多相關內容的文章,歡迎關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。