首頁 > 科技

解放雙手|Python 批量自動提取、整理 PDF 發票

2021-06-15 15:29:53

來源:早起Python

作者:陳熹

大家好,我是早起。

本文分享一個基於 PDF 的 Python 辦公自動化的案例解決,也是某位財務小姐姐提出的真實需求,先來看看需求。

需求描述

在某個資料夾下有多個PDF類型發票

每一張發票PDF是

純圖片

類型,裡面的文字資訊無法手動複製(事實上大多數發票可以複製部分文字,但我們扔以圖片形式來講解),大致如下圖所示:

需要滿足的需求是:獲取

總金額、納稅人識別號、開票人,即如下三個方框位置:

最後結合批量操作,在獲取上述資訊後將其儲存入Excel中!

思路與程式碼實現

需求本質是一個圖片識別問題,因為 PDF 裡的內容是圖片類型,無法按常規方法直接把文字抽提出來。解決思路是利用光學字元識別(OCR)將圖片中的文字識別出。但同時也需要注意,PDF 畢竟不是圖片,為了完成 OCR,除了OCR自身之外還要下載

Ghostscript和ImageMagick用來完成類型轉換。已Windows系統為例,需要在電腦上安裝以下三個軟體:

Ghostscript

32 位

ImageMagick

32 位

tesseract-OCR

32 位

三個軟體的下載安裝沒有特殊的地方(tesseract 配置稍複雜但網路有上諸多教程,這裡不再贅述),讀者可自行搜尋下載及配置,下面講解程式碼。首先匯入需要的模組:

from wand.image import Imagefrom PIL import Image as PIimport pyocrimport pyocr.buildersimport ioimport reimport osimport shutil

具體的模組用途可以參考下面具體程式碼。其中wand和pyocr

由於是非標準庫需要自行額外安裝。開啟命令列輸入:

pip install wandpip install pyocr

本需求還涉及對接 Excel,可考慮利用openpyxl庫的Workbook

用以創建新的 Excel 檔案:

from openpyxl import Workbook需求中的發票.pdf放在桌面上。可通過下面基於os模組的程式碼獲取桌面路徑:

# 獲取桌面路徑包裝成一個函數def GetDesktopPath():return os.path.join(os.path.expanduser("~"), 'Desktop')path = GetDesktopPath() + r'發票.pdf'獲取配置好的tesseract便於後面呼叫:

tool = pyocr.get_available_tools()[0]通過wand模組將 PDF 檔案轉化為解析度為 300 的jpeg

圖片形式:

image_pdf = Image(filename=path, resolution=300)image_jpeg = image_pdf.convert('jpeg')

將圖片解析為二進位制矩陣:

image_lst = []for img in image_jpeg.sequence:img_page = Image(image=img) image_lst.append(img_page.make_blob('jpeg'))

用io模組的BytesIO方法讀取二進位制內容為圖片形式:

new_img = PI.open(io.BytesIO(image_lst[0]))

new_img.show()

接下來分別擷取需要提取部位字元串的圖片了,儘量讓圖片中只有需要識別的部分,獲取識別出來容易簡單處理獲得需要的內容。

首先以總金額為例,擷取圖片用image.crop((left, top, right, bottom))

四個參數需要反覆偵錯才能確定。經確定四個參數分別是 1600 760 1830 900,嘗試擷取和預覽圖片:

### 解析1Z開頭碼left = 350top = 600right = 1300bottom = 730image_obj1 = new_img.crop((left, top, right, bottom))image_obj1.show()

擷取成功後可以交給 OCR 了,程式碼為

tool.image_to_string()

txt1= tool.image_to_string(image_obj1)print(txt1)

同樣,通過方位的偵錯就可以準確切割到需要的部分進行識別:

left = 560top = 1260right = 900bottom = 1320image_obj2 = new_img.crop((left, top, right, bottom))# image_obj2.show()txt2 = tool.image_to_string(image_obj2)# print(txt2)

最後是開票人的識別

left = 1420

top = 1420right = 1700bottom = 1500image_obj3 = new_img.crop((left, top, right, bottom))# image_obj3.show()txt3 = tool.image_to_string(image_obj3)# print(txt3)

需要確認識別的內容是否正確,如果識別正確率欠佳可以考慮通過圖片處理技術消除噪聲,也可以去官網下載更高精度的訓練包提高識別的正確性

至此,我們成功的識別了總金額、納稅人識別號、開票人三個訊息,接下來就通過非常熟悉的openpyxl寫入Excel,並使用os模組實現批量操作即可

workbook = Workbook()sheet = workbook.activeheader = ['總金額', '納稅人識別號', '開票人']sheet.append(header)sheet.append([txt1, txt2, txt3])workbook.save(GetDesktopPath() + r'彙總.xlsx')

綜上,整個需求就成功實現,從效果來看還是非常不錯的!完整源碼可由文中程式碼組合而成(已全部分享在文中),感興趣的讀者可以自己嘗試!

最後想說的是,其實本文的案例可以衍生出很多實用的辦公自動化指令碼,例如

批量計算髮票金額並重命名資料夾根據發票類型批量分類根據發票批量製作報銷單··· ···


IT145.com E-mail:sddin#qq.com