Python提取PDF發(fā)票信息保存Excel文件并制作EXE程序的全過程
前言
通過本篇文章可學(xué)習(xí)pdf發(fā)票信息的提取,內(nèi)容保存至Excel,了解命令圖像工具Gooey,以及如何將python文件打包為exe程序
背景
現(xiàn)在電子發(fā)票越來越普遍,各公司開票形式已基本無紙化。目前所在公司的情況是,每個人自己報賬,需要將發(fā)票信息(發(fā)票號/金額)填如K3系統(tǒng)進行流程申請,另外將電子發(fā)票打印為紙質(zhì)并貼票后找領(lǐng)導(dǎo)簽字及審批K3的流程;之后在將紙質(zhì)單據(jù)送至財務(wù)審批。如果財務(wù)發(fā)現(xiàn)數(shù)據(jù)填寫不正確,就會將流程和單據(jù)打回來,又要重新找領(lǐng)導(dǎo)簽字審批,相當(dāng)麻煩。
分析
為了減少報賬被打回來的情況,我們先分析,整個報賬過程中,存在的問題
下載回來的發(fā)票文件命名不規(guī)范不容易識別
如:04500160011131347550.pdf
填K3時需要復(fù)制發(fā)票號和金額,還要選擇發(fā)票類型
每次要打開pdf發(fā)票復(fù)制發(fā)票號和金額
發(fā)票可能存在錯誤情況:如公司名稱或納稅人識別號不正確
每次還要檢查一下
優(yōu)化
一開始的想法是,做一個程序,識別發(fā)票信息并提供復(fù)制按鈕,方便復(fù)制到k3。自動檢查發(fā)票信息是否完整正確,公司名稱和納稅人識別號是否正確,如不正確則提示錯誤,另外自動將文件重名稱,及一鍵打印功能。
不過由于對Python的GUI還不大熟悉,就改了方式:將發(fā)票信息提取至Excel,在自己到Excel上復(fù)制信息和檢查發(fā)票是否完整,另外將文件重命名為開票公司+金額的形式
最終效果



實現(xiàn)
讀取pdf發(fā)票
使用pdfplumber,安裝命令pip install pdfplumber,
import pdfplumber
import re
import os
def re_text(bt, text):
m1 = re.search(bt, text)
if m1 is not None:
return re_block(m1[0])
def re_block(text):
return text.replace(' ', '').replace(' ', '').replace(')', '').replace(')', '').replace(':', ':')
def get_pdf(dir_path):
pdf_file = []
for root, sub_dirs, file_names in os.walk(dir_path):
for name in file_names:
if name.endswith('.pdf'):
filepath = os.path.join(root, name)
pdf_file.append(filepath)
return pdf_file
def read():
filenames = get_pdf('C:\Users\Administrator\Desktop\a') # 修改為自己的文件目錄
for filename in filenames:
print(filename)
with pdfplumber.open(filename) as pdf:
first_page = pdf.pages[0]
pdf_text = first_page.extract_text()
if '發(fā)票' not in pdf_text:
continue
# print(pdf_text)
print('--------------------------------------------------------')
print(re_text(re.compile(r'[\u4e00-\u9fa5]+電子普通發(fā)票.*?'), pdf_text))
t2 = re_text(re.compile(r'[\u4e00-\u9fa5]+專用發(fā)票.*?'), pdf_text)
if t2:
print(t2)
# print(re_text(re.compile(r'發(fā)票代碼(.*\d+)'), pdf_text))
print(re_text(re.compile(r'發(fā)票號碼(.*\d+)'), pdf_text))
print(re_text(re.compile(r'開票日期(.*)'), pdf_text))
print(re_text(re.compile(r'名\s*稱\s*[::]\s*([\u4e00-\u9fa5]+)'), pdf_text))
print(re_text(re.compile(r'納稅人識別號\s*[::]\s*([a-zA-Z0-9]+)'), pdf_text))
price = re_text(re.compile(r'小寫.*(.*[0-9.]+)'), pdf_text)
print(price)
company = re.findall(re.compile(r'名.*稱\s*[::]\s*([\u4e00-\u9fa5]+)'), pdf_text)
if company:
print(re_block(company[len(company)-1]))
print('--------------------------------------------------------')
read()通過上述代碼可以實現(xiàn)對pdf發(fā)票的內(nèi)容識別和輸出功能,完整的功能請通過學(xué)習(xí)本文后續(xù)的內(nèi)容自主實現(xiàn)。
寫入Excel
使用xlwt寫Excel文件,安裝命令pip install xlwt,一個簡單的例子如下
import xlwt
# 創(chuàng)建工作簿
wb = xlwt.Workbook()
# 創(chuàng)建表單
sh = wb.add_sheet('sheet 1')
# 寫入數(shù)據(jù)
sh.write(0, 1, '姓名')
# 保存
wb.save('test.xls')創(chuàng)建圖像界面
使用Gooey創(chuàng)建GUI圖像界面,安裝命令pip install Gooey
官網(wǎng)地址:https://github.com/chriskiehl/Gooey 目前是:15.4k stars
這里對Gooey的適用情況做一個說明,Gooey適用于命令行的圖形工具,也就是只做輸入(有各種輸入/選擇框)和輸出的情況,不適用于做界面展示,無法添加自定義按鈕,如button等。使用print就能將輸出內(nèi)容顯示到GUI圖形界面上
一個簡單的例子
from gooey import Gooey, GooeyParser
@Gooey(program_name="簡單的實例")
def main():
parser = GooeyParser(description="第一個示例!")
parser.add_argument('文件路徑', widget="FileChooser") # 文件選擇框
parser.add_argument('日期', widget="DateChooser") # 日期選擇框
args = parser.parse_args() # 接收界面?zhèn)鬟f的參數(shù)
print(args)
if__name__ == '__main__':
main()
打包為exe文件
使用pyinstaller將代碼打包為exe文件
安裝命令pip install pyinstaller
打包命令pyinstaller -F xxxxx.py -w (xxxxx.py改為具體的.py文件名)
等待打包完成,在代碼目錄的會生成dist文件夾,打開后可以看到exe程序

注意:程序有中文輸出的請查看該文章,避免打包后程序無法正常運行,參考如下
附:解決Gooey在打包成exe文件后打印中文報UnicodeDecodeError: 'utf-8' codec can't decode
問題
在使用Gooey這個工具生成GUI的時候,沒有打包前測試是好的,但是當(dāng)打包成exe文件后,雙擊exe運行填入所需選項執(zhí)行報UnicodeDecodeError: 'utf-8' codec can't decode的錯誤。
PS C:\Users\faces\Desktop\gooey demo\dist> .\auto.exe
Exception in thread Thread-1:
Traceback (most recent call last):
File "threading.py", line 926, in _bootstrap_inner
File "threading.py", line 870, in run
File "site-packages\gooey\gui\processor.py", line 71, in _forward_stdout
File "site-packages\gooey\gui\processor.py", line 84, in _extract_progress
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xb5 in position 13: invalid start byte
通過查找github中提交的issue發(fā)現(xiàn)是打包后環(huán)境的encoding與打包時的encoding不一致導(dǎo)致的問題。
解決方案
在Gooey裝飾器中加入關(guān)鍵字參數(shù)encoding='cp936'
from gooey import Gooey, GooeyParser
@Gooey(encoding='cp936')
def main():
parser = GooeyParser(description="Export music lite")
parser.add_argument('exe文件', widget="FileChooser")
parser.add_argument('flac文件夾', widget="DirChooser")
parser.add_argument('MP3導(dǎo)出文件夾', widget="DirChooser")
args = parser.parse_args()
print(args)
if __name__ == "__main__":
main()
問題
接下來我想更改Gooey生成的GUI頁面為中文,那么代碼改為
from gooey import Gooey, GooeyParser
@Gooey(encoding='cp936', language='chinese')
def main():
parser = GooeyParser(description="Export music lite")
...
這時候執(zhí)行會報如下錯誤
PS C:\Users\faces\Desktop\gooey demo\dist> .\auto.exe
Traceback (most recent call last):
File "auto.py", line 17, in <module>
File "site-packages\gooey-1.0.3-py3.7.egg\gooey\python_bindings\gooey_decorator.py", line 87, in inner2
File "auto.py", line 12, in main
File "site-packages\gooey-1.0.3-py3.7.egg\gooey\python_bindings\gooey_parser.py", line 114, in parse_args
File "site-packages\gooey-1.0.3-py3.7.egg\gooey\python_bindings\gooey_decorator.py", line 82, in run_gooey
File "site-packages\gooey-1.0.3-py3.7.egg\gooey\gui\application.py", line 21, in run
File "site-packages\gooey-1.0.3-py3.7.egg\gooey\gui\application.py", line 28, in build_app
File "site-packages\gooey-1.0.3-py3.7.egg\gooey\gui\lang\i18n.py", line 24, in load
File "json\__init__.py", line 293, in load
UnicodeDecodeError: 'gbk' codec can't decode byte 0xa7 in position 20: illegal multibyte sequence
解決方案
從報錯信息中可以看到是因為load代碼的時候使用encoding='cp936'去加載文件導(dǎo)致的錯誤,那么簡單粗暴的方法是編輯site-packages\gooey-1.0.3-py3.7.egg\gooey\gui\lang\i18n.py這個文件
找到
with io.open(os.path.join(language_dir, json_file), 'r', encoding=encoding) as f:
_DICTIONARY = json.load(f)
修改為
with io.open(os.path.join(language_dir, json_file), 'r', encoding='utf-8') as f:
_DICTIONARY = json.load(f)
總結(jié)
到此這篇關(guān)于Python提取PDF發(fā)票信息保存Excel文件并制作EXE程序的文章就介紹到這了,更多相關(guān)Python提取PDF發(fā)票信息保存Excel內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
在pytorch中如何查看模型model參數(shù)parameters
這篇文章主要介紹了在pytorch中如何查看模型model參數(shù)parameters,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-11-11
python 刪除系統(tǒng)中的文件(按時間,大小,擴展名)
這篇文章主要介紹了python 如何刪除系統(tǒng)中的文件,分別按時間,大小,擴展名刪除,滿足不同需求,感興趣的朋友可以了解下2020-11-11
python opencv將圖片轉(zhuǎn)為灰度圖的方法示例
這篇文章主要介紹了python opencv將圖片轉(zhuǎn)為灰度圖的方法示例,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-07-07
將pymysql獲取到的數(shù)據(jù)類型是tuple轉(zhuǎn)化為pandas方式
這篇文章主要介紹了將pymysql獲取到的數(shù)據(jù)類型是tuple轉(zhuǎn)化為pandas方式,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-05-05
Python 聊聊socket中的listen()參數(shù)(數(shù)字)到底代表什么
本篇文章對Python 聊聊socket中的listen()參數(shù)(數(shù)字)到底代表什么,進行了很好的講解,希望對大家有所幫助。一起跟隨小編過來看看吧2021-04-04
django如何連接已存在數(shù)據(jù)的數(shù)據(jù)庫
這篇文章主要給大家介紹了關(guān)于django如何連接已存在數(shù)據(jù)的數(shù)據(jù)庫的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家學(xué)習(xí)或者使用django具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2018-08-08
python 實現(xiàn)長數(shù)據(jù)完整打印方案
這篇文章主要介紹了python 實現(xiàn)長數(shù)據(jù)完整打印方案,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2021-03-03
Python中的shutil標(biāo)準(zhǔn)庫用法解析
這篇文章主要介紹了Python中的shutil標(biāo)準(zhǔn)庫用法解析,shutil模塊提供了許多關(guān)于文件和文件集合的高級操作,特別提供了支持文件復(fù)制和刪除的功能,需要的朋友可以參考下2023-09-09

