新聞中心
今天的具體內(nèi)容將會(huì)從以下幾個(gè)小節(jié)展開(kāi):

10年積累的網(wǎng)站設(shè)計(jì)、做網(wǎng)站經(jīng)驗(yàn),可以快速應(yīng)對(duì)客戶對(duì)網(wǎng)站的新想法和需求。提供各種問(wèn)題對(duì)應(yīng)的解決方案。讓選擇我們的客戶得到更好、更有力的網(wǎng)絡(luò)服務(wù)。我雖然不認(rèn)識(shí)你,你也不認(rèn)識(shí)我。但先網(wǎng)站設(shè)計(jì)后付款的網(wǎng)站建設(shè)流程,更有將樂(lè)免費(fèi)網(wǎng)站建設(shè)讓你可以放心的選擇與我們合作。
- 相關(guān)介紹
- 批量拆分
- 批量合并
- 提取文字內(nèi)容
- 提起表格內(nèi)容
- 提起圖片內(nèi)容
- 轉(zhuǎn)換為PDF圖片
- 添加水印
- 加密與解碼
上述操作比較常用,也可以解決較多的辦公內(nèi)容,下面直接開(kāi)始本節(jié)內(nèi)容:
1. 相關(guān)介紹
Python 操作 PDF 會(huì)用到兩個(gè)庫(kù),分別是:PyPDF2 和 pdfplumber。
其中 PyPDF2 可以更好的讀取、寫入、分割、合并PDF文件,而 pdfplumber 可以更好的讀取 PDF 文件中內(nèi)容和提取 PDF 中的表格。
對(duì)應(yīng)的官網(wǎng)分別是:
- PyPDF2:https://pythonhosted.org/PyPDF2/
- pdfplumber:https://github.com/jsvine/pdfplumber
由于這兩個(gè)庫(kù)都不是 Python 的標(biāo)準(zhǔn)庫(kù),所以在使用之前都需要單獨(dú)安裝。
win+r 后輸入 cmd 打開(kāi) command 窗口,依次輸入如下命令進(jìn)行安裝:
- pip install PyPDF2
- pip install pdfplumber
安裝完成后顯示 success 則表示安裝成功。
2. 批量拆分
將一個(gè)完整的 PDF 拆分成幾個(gè)小的 PDF,因?yàn)橹饕婕暗?PDF 整體的操作,所以本小節(jié)需要用到 PyPDF2 這個(gè)庫(kù)。
拆分的大概思路如下:
- 讀取 PDF 的整體信息、總頁(yè)數(shù)等
- 遍歷每一頁(yè)內(nèi)容,以每個(gè) step 為間隔將 PDF 存成每一個(gè)小的文件塊
- 將小的文件塊重新保存為新的 PDF 文件
需要注意的是,在拆分的過(guò)程中,可以手動(dòng)設(shè)置間隔,例如:每5頁(yè)保存成一個(gè)小的 PDF 文件。
拆分的代碼如下:
import os
from PyPDF2 import PdfFileWriter, PdfFileReader
def split_pdf(filename, filepath, save_dirpath, step=5):
"""
拆分PDF為多個(gè)小的PDF文件,
@param filename:文件名
@param filepath:文件路徑
@param save_dirpath:保存小的PDF的文件路徑
@param step: 每step間隔的頁(yè)面生成一個(gè)文件,例如step=5,表示0-4頁(yè)、5-9頁(yè)...為一個(gè)文件
@return:
"""
if not os.path.exists(save_dirpath):
os.mkdir(save_dirpath)
pdf_reader = PdfFileReader(filepath)
# 讀取每一頁(yè)的數(shù)據(jù)
pages = pdf_reader.getNumPages()
for page in range(0, pages, step):
pdf_writer = PdfFileWriter()
# 拆分pdf,每 step 頁(yè)的拆分為一個(gè)文件
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)
以“易方達(dá)中小盤混合型證券投資基金2020年中期報(bào)告”為例,整個(gè) PDF 文件一共 46 頁(yè),每5頁(yè)為間隔,最終生成了10個(gè)小的 PDF 文件。
3. 批量合并
比起拆分來(lái),合并的思路更加簡(jiǎn)單:
- 確定要合并的 文件順序
- 循環(huán)追加到一個(gè)文件塊中
- 保存成一個(gè)新的文件
對(duì)應(yīng)的代碼比較簡(jiǎn)單:
import os
from PyPDF2 import PdfFileReader, PdfFileWriter
def concat_pdf(filename, read_dirpath, save_filepath):
"""
合并多個(gè)PDF文件
@param filename:文件名
@param read_dirpath:要合并的PDF目錄
@param save_filepath:合并后的PDF文件路徑
@return:
"""
pdf_writer = PdfFileWriter()
# 對(duì)文件名進(jìn)行排序
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)
# 讀取文件并獲取文件的頁(yè)數(shù)
pdf_reader = PdfFileReader(filepath)
pages = pdf_reader.getNumPages()
# 逐頁(yè)添加
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)
4. 提取文字內(nèi)容
涉及到具體的 PDF 內(nèi)容 操作,本小節(jié)需要用到 pdfplumber 這個(gè)庫(kù)。
在進(jìn)行文字提取的時(shí)候,主要用到 extract_text 這個(gè)函數(shù)。
具體代碼如下:
import os
import pdfplumber
def extract_text_info(filepath):
"""
提取PDF中的文字
@param filepath:文件路徑
@return:
"""
with pdfplumber.open(filepath) as pdf:
# 獲取第2頁(yè)數(shù)據(jù)
page = pdf.pages[1]
print(page.extract_text())
# 提取文字內(nèi)容
extract_text_info(filepath)
可以看到,直接通過(guò)下標(biāo)即可定位到相應(yīng)的頁(yè)碼,從而通過(guò) extract_text 函數(shù)提取該也的所有文字。
而如果想要提取所有頁(yè)的文字,只需要改成:
with pdfplumber.open(filepath) as pdf:
# 獲取全部數(shù)據(jù)
for page in pdf.pages
print(page.extract_text())
例如,提取“易方達(dá)中小盤混合型證券投資基金2020年中期報(bào)告” 第一頁(yè)的內(nèi)容時(shí),源文件是這樣的:
運(yùn)行代碼后提取出來(lái)是這樣的:
5. 提取表格內(nèi)容
同樣的,本節(jié)是對(duì)具體內(nèi)容的操作,所以也需要用到 pdfplumber 這個(gè)庫(kù)。
和提取文字十分類似的是,提取表格內(nèi)容只是將 extract_text 函數(shù)換成了 extract_table 函數(shù)。
對(duì)應(yīng)的代碼如下:
import os
import pandas as pd
import pdfplumber
def extract_table_info(filepath):
"""
提取PDF中的圖表數(shù)據(jù)
@param filepath:
@return:
"""
with pdfplumber.open(filepath) as pdf:
# 獲取第18頁(yè)數(shù)據(jù)
page = pdf.pages[17]
# 如果一頁(yè)有一個(gè)表格,設(shè)置表格的第一行為表頭,其余為數(shù)據(jù)
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')
# 提取表格內(nèi)容
extract_table_info(filepath)
上面代碼可以獲取到第 18 頁(yè)的第一個(gè)表格內(nèi)容,并且將其保存為 csv 文件存在本地。
- 但是,如果說(shuō)第 18 頁(yè)有多個(gè)表格內(nèi)容呢?
因?yàn)樽x取的表格會(huì)被存成二維數(shù)組,而多個(gè)二維數(shù)組就組成一個(gè)三維數(shù)組。
遍歷這個(gè)三位數(shù)組,就可以得到該頁(yè)的每一個(gè)表格數(shù)據(jù),對(duì)應(yīng)的將 extract_table 函數(shù) 改成 extract_tables 即可。
具體代碼如下:
# 如果一頁(yè)有多個(gè)表格,對(duì)應(yīng)的數(shù)據(jù)是一個(gè)三維數(shù)組
tables_info = page.extract_tables()
for index in range(len(tables_info)):
# 設(shè)置表格的第一行為表頭,其余為數(shù)據(jù)
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')
以“易方達(dá)中小盤混合型證券投資基金2020年中期報(bào)告” 第 xx 頁(yè)的第一個(gè)表格為例:
源文件中的表格是這樣的:
提取并存入 excel 之后的表格是這樣的:
6. 提取圖片內(nèi)容
提取 PDF 中的圖片和將 PDF 轉(zhuǎn)存為圖片是不一樣的(下一小節(jié)),需要區(qū)分開(kāi)。
提取圖片:顧名思義,就是將內(nèi)容中的圖片都提取出來(lái);
轉(zhuǎn)存為圖片:則是將每一頁(yè)的 PDF 內(nèi)容存成一頁(yè)一頁(yè)的圖片,下一小節(jié)會(huì)詳細(xì)說(shuō)明
轉(zhuǎn)存為圖片中,需要用到一個(gè)模塊叫 fitz,fitz 的最新版 1.18.13,非最新版的在部分函數(shù)名稱上存在差異,代碼中會(huì)標(biāo)記出來(lái)
使用 fitz 需要先安裝 PyMuPDF 模塊,安裝方式如下:
- pip install PyMuPDF
提取圖片的整體邏輯如下:
- 使用 fitz 打開(kāi)文檔,獲取文檔詳細(xì)數(shù)據(jù)
- 遍歷每一個(gè)元素,通過(guò)正則找到圖片的索引位置
- 使用 Pixmap 將索引對(duì)應(yīng)的元素生成圖片
- 通過(guò) size 函數(shù)過(guò)濾較小的圖片
實(shí)現(xiàn)的具體代碼如下:
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)
# 使用正則表達(dá)式來(lái)查找圖片
check_XObject = r"/Type(?= */XObject)"
check_Image = r"/Subtype(?= */Image)"
img_count = 0
"""1. 打開(kāi)pdf,打印相關(guān)信息"""
pdf_info = fitz.open(filepath)
# 1.16.8版本用法 xref_len = doc._getXrefLength()
# 最新版本
xref_len = pdf_info.xref_length()
# 打印PDF的信息
print("文件名:{}, 頁(yè)數(shù): {}, 對(duì)象: {}".format(filepath, len(pdf_info), xref_len-1))
"""2. 遍歷PDF中的對(duì)象,遇到是圖像才進(jìn)行下一步,不然就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)
# 如果不是對(duì)象也不是圖片,則不操作
if is_XObject or is_Image:
img_count += 1
# 根據(jù)索引生成圖像
pix = fitz.Pixmap(pdf_info, index)
pic_filepath = os.path.join(pic_dirpath, 'img_' + str(img_count) + '.png')
"""pix.size 可以反映像素多少,簡(jiǎn)單的色素塊該值較低,可以通過(guò)設(shè)置一個(gè)閾值過(guò)濾。以閾值 10000 為例過(guò)濾"""
# if pix.size < 10000:
# continue
"""三、 將圖像存為png格式"""
if pix.n >= 5:
# 先轉(zhuǎn)換CMYK
pix = fitz.Pixmap(fitz.csRGB, pix)
# 存為PNG
pix.writePNG(pic_filepath)
# 提取圖片內(nèi)容
extract_pic_info(filepath, pic_dirpath)
以本節(jié)示例的“易方達(dá)中小盤混合型證券投資基金2020年中期報(bào)告” 中的圖片為例,代碼運(yùn)行后提取的圖片如下:
這個(gè)結(jié)果和文檔中的共 1 張圖片的結(jié)果符合。
7. 轉(zhuǎn)換為圖片
轉(zhuǎn)換為照片比較簡(jiǎn)單,就是將一頁(yè)頁(yè)的 PDF 轉(zhuǎn)換為一張張的圖片。大致過(guò)程如下:
安裝 pdf2image
首先需要安裝對(duì)應(yīng)的庫(kù),最新的 pdf2image 庫(kù)版本應(yīng)該是 1.14.0。
它的 github地址 為:https://github.com/Belval/pdf2image ,感興趣的可以自行了解。
安裝方式如下:
- pip install pdf2image
安裝組件
對(duì)于不同的平臺(tái),需要安裝相應(yīng)的組件,這里以 windows 平臺(tái)和 mac 平臺(tái)為例:
Windows 平臺(tái)
對(duì)于 windows 用戶需要安裝 poppler for Windows,安裝鏈接是:http://blog.alivate.com.au/poppler-windows/
另外,還需要添加環(huán)境變量, 將 bin 文件夾的路徑添加到環(huán)境變量 PATH 中。
- 注意這里配置之后需要重啟一下電腦才會(huì)生效,不然會(huì)報(bào)錯(cuò)
Mac
對(duì)于 mac 用戶,需要安裝 poppler for Mac,具體可以參考這個(gè)鏈接:http://macappstore.org/poppler/
詳細(xì)代碼如下:
import os
from pdf2image import convert_from_path, convert_from_bytes
def convert_to_pic(filepath, pic_dirpath):
"""
每一頁(yè)的PDF轉(zhuǎn)換成圖片
@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轉(zhuǎn)換為圖片
convert_to_pic(filepath, pic_dirpath)
以本節(jié)示例的“易方達(dá)中小盤混合型證券投資基金2020年中期報(bào)告” 中的圖片為例,該文檔共 46 頁(yè),保存后的 PDF 照片如下:
一共 46 張圖片
8. 添加水印
添加水印后的效果如下:
在制作水印的時(shí)候,可以自定義水印內(nèi)容、透明度、斜度、字間寬度等等,可操作性比較好。
前面專門寫過(guò)一篇文章,講的特別詳細(xì):Python快速給PDF文件添加自定義水印。
9. 文檔加密與解密
你可能在打開(kāi)部分 PDF 文件的時(shí)候,會(huì)彈出下面這個(gè)界面:
這種就是 PDF 文件被加密了,在打開(kāi)的時(shí)候需要相應(yīng)的密碼才行。
本節(jié)所提到的也只是基于 PDF 文檔的加密解密,而不是所謂的 PDF 密碼破解。
在對(duì) PDF 文件加密需要使用 encrypt 函數(shù),對(duì)應(yīng)的加密代碼也比較簡(jiǎn)單:
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')
代碼執(zhí)行成功后再次打開(kāi) PDF 文件則需要輸入密碼才行。
根據(jù)這個(gè)思路,破解 PDF 也可以通過(guò)暴力求解實(shí)現(xiàn),例如:通過(guò)本地密碼本一個(gè)個(gè)去嘗試,或者根據(jù)數(shù)字+字母的密碼形式循環(huán)嘗試,最終成功打開(kāi)的密碼就是破解密碼。
- 上述破解方法耗時(shí)耗力,不建議嘗試
另外,針對(duì)已經(jīng)加密的 PDF 文件,也可以使用 decrypt 函數(shù)進(jìn)行解密操作。
解密代碼如下:
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 文檔打開(kāi)后不再需要輸入密碼,如需加密可再次執(zhí)行加密代碼。
以上就是 Python 操作 PDF 的全部?jī)?nèi)容,文中貼出的代碼都已經(jīng)測(cè)試過(guò),可正常運(yùn)行。
當(dāng)前標(biāo)題:Python 辦公自動(dòng)化之 PDF 的詳細(xì)操作
瀏覽地址:http://www.5511xx.com/article/cdssise.html


咨詢
建站咨詢
