今天我們繼續分享真實的自動化辦公案例,希望各位 Python 愛好者能夠從中得到些許啟發,在自己的工作生活中更多的應用 Python,使得工作事半功倍!
需求
需要從 PDF 中取出幾頁并將其保存為新的 PDF,為了后期使用方便,這個工具需要做成傻瓜式的帶有 GUI 頁面的形式
選擇源 pdf 文件,再指定下生成的新的 pdf 文件名稱及保存位置,和需要拆分的 page 信息,就可以得到新的 pdf 文件了
需求解析
對于 Python GUI,我們有太多種選擇了,下面我們先來橫向的簡單對比下
從高層次上看,大的 GUI 工具有:
Qt
WxWindows
Tkinter
Customer libraries(Kivy,Toga等)
Web相關(HTML,Flask等)
不過今天,我們選擇的工具是 appJar,這是一個由一位從事教育工作的大神發明的,所以它可以提供一個更加簡單的 GUI 創建過程,而且是完全基于 Tkinter 的,Python 默認支持
代碼實現
首先為了實現 PDF 操作,我這里選擇了 pypdf2 庫
我們先硬編碼一個輸入輸出的示例
fromPyPDF2importPdfFileWriter,?PdfFileReader
infile?="Input.pdf"
outfile?="Output.pdf"
page_range?="1-2,6"
接下來我們實例化 PdfFileWriter 和 PdfFIleReader 對象,并創建實際的 Output.pdf 文件
output?=?PdfFileWriter()
input_pdf?=?PdfFileReader(open(infile,"rb"))
output_file?=?open(outfile,"wb")
下面一個比較復雜的點就是需要拆分 pdf,提取頁面并保存在列表中
page_ranges?=?(x.split("-")forxinpage_range.split(","))
range_list?=?[iforrinpage_rangesforiinrange(int(r[0]),?int(r[-1])?+1)]
最后就是從原始文件中拷貝內容到新的文件
forpinrange_list:
output.addPage(input_pdf.getPage(p?-1))
output.write(output_file)
下面來構建 GUI 界面
對于這個拆分 PDF 的小工具,需要具有如下功能:
可以通過標準文件瀏覽器選擇 pdf 文件
可以選擇輸出文件的位置及文件名稱
可以自定義提取哪些頁面
有一些錯誤檢查
通過 PIP 安裝好 appJar 后,我們就可以編碼了
fromappJarimportgui
fromPyPDF2importPdfFileWriter,?PdfFileReader
frompathlibimportPath
創建 GUI 窗口
app?=?gui("PDF?Splitter",?useTtk=True)
app.setTtkTheme("default")
app.setSize(500,200)
這里我使用了默認主題,當然也可以切換各種各樣的主題模式
下面是添加標簽和數據輸入組件
app.addLabel("Choose?Source?PDF?File")
app.addFileEntry("Input_File")
app.addLabel("Select?Output?Directory")
app.addDirectoryEntry("Output_Directory")
app.addLabel("Output?file?name")
app.addEntry("Output_name")
app.addLabel("Page?Ranges:?1,3,4-10")
app.addEntry("Page_Ranges")
接下來添加按鈕,“處理”和“退出”,按下按鈕,調用如下函數
app.addButtons(["Process","Quit"],?press)
最后就是運行這個 app 啦
#?start?the?GUI
app.go()
這樣我們就完成了 GUI 的搭建,下面編寫內部處理邏輯。程序讀取任何輸入,判斷是否為 PDF,并拆分
defpress(button):
ifbutton?=="Process":
src_file?=?app.getEntry("Input_File")
dest_dir?=?app.getEntry("Output_Directory")
page_range?=?app.getEntry("Page_Ranges")
out_file?=?app.getEntry("Output_name")
errors,?error_msg?=?validate_inputs(src_file,?dest_dir,?page_range,?out_file)
iferrors:
app.errorBox("Error","\n".join(error_msg),?parent=None)
else:
split_pages(src_file,?page_range,?Path(dest_dir,?out_file))
else:
app.stop()
如果單擊 “處理(Process)”按鈕,則調用 app.getEntry() 檢索輸入值,每個值都會被存儲,然后通過調用 validate_inputs() 進行驗證
來看看 validate_inputs 函數
defvalidate_inputs(input_file,?output_dir,?range,?file_name):
errors?=False
error_msgs?=?[]
#?Make?sure?a?PDF?is?selected
ifPath(input_file).suffix.upper()?!=".PDF":
errors?=True
error_msgs.append("Please?select?a?PDF?input?file")
#?Make?sure?a?range?is?selected
iflen(range)?<1:
errors?=True
error_msgs.append("Please?enter?a?valid?page?range")
#?Check?for?a?valid?directory
ifnot(Path(output_dir)).exists():
errors?=True
error_msgs.append("Please?Select?a?valid?output?directory")
#?Check?for?a?file?name
iflen(file_name)?<1:
errors?=True
error_msgs.append("Please?enter?a?file?name")
return(errors,?error_msgs)
這個函數就是執行一些檢查來確保輸入有數據并且有效
在收集驗證了所有數據后,就可以調用 split 函數來處理文件了
defsplit_pages(input_file,?page_range,?out_file):
output?=?PdfFileWriter()
input_pdf?=?PdfFileReader(open(input_file,"rb"))
output_file?=?open(out_file,"wb")
page_ranges?=?(x.split("-")forxinpage_range.split(","))
range_list?=?[iforrinpage_rangesforiinrange(int(r[0]),?int(r[-1])?+1)]
forpinrange_list:
#?Need?to?subtract?1?because?pages?are?0?indexed
try:
output.addPage(input_pdf.getPage(p?-1))
exceptIndexError:
#?Alert?the?user?and?stop?adding?pages
app.infoBox("Info","Range?exceeded?number?of?pages?in?input.\nFile?will?still?be?saved.")
break
output.write(output_file)
if(app.questionBox("File?Save","Output?PDF?saved.?Do?you?want?to?quit?")):
app.stop()
好了,這樣我們就完成了一個簡易的 GUI 拆分 PDF 文件的工具嘍
喜歡就點贊+轉發,支持一下噻!