使用Python第三方庫pdfminer提取PDF內容,並解決中文編碼不支持的問題
這兩天剛好完成一個提取人行簡版徵信報告PDF所有數據的小項目,中間踩了很多坑,尤其是對於漢字編碼問題度娘也不太靈。為了方便後人,在這裡記錄下在這個過程中我遇到的問題以及我的解決方法。
我用的是mac系統,Python 3.6,依賴第三方庫pdfminer3k 1.3.1。這個是pdfminer的python 3.x版本,原始版為pdfminer,只支持python2 .x。
如果想要支持中日韓文字,這個庫絕對不可pip安裝。如何安裝我後面介紹,在這裡先吐槽一句,為啥utf-8很多個漢字對應著兩套編碼啊!!這個設定真是很坑啊!!如果看不懂吐槽沒關係,你可以試著解析一下你自己的簡版報告就懂了。。。
這個庫的使用還是比較簡單的,網上有很多的使用方法我就不重複了。其實開發者打包了一個腳本pdf2txt.py,裡面包含了這個庫的眾多使用方法,看一遍就會用。在這裡貼上我的代碼:
from pdfminer.pdfinterp import PDFResourceManager, process_pdffrom pdfminer.converter import TextConverter, HTMLConverterfrom pdfminer.layout import LAParamsfrom io import StringIO, openimport osdef readPDF(file_name): rsrcmgr = PDFResourceManager() retstr = StringIO() laparams = LAParams(all_texts = True) device = TextConverter(rsrcmgr, retstr, laparams=laparams) file = open(file_name, rb) process_pdf(rsrcmgr, device, file) file.close() device.close() content = retstr.getvalue().split(
) retstr.close() for i in range(len(content)): content[i] = content[i].strip() if content[i].startswith(第) and content[i].endswith(頁): content[i]= if content[i].startswith(共) and content[i].endswith(頁): content[i]= while in content: content.remove() return content
運行完得到一個含有這個PDF所有文字信息的list,我的心中一陣狂喜,這不就是我想要的嘛,接下來使用正則大法提取相關內容就好了嘛!事實證明我還是太年輕。。。
這個包最大的坑就是漢字編碼,具體是這樣嬸兒的:
我得到的content里第i行是字元串2017年1月1日XXXX(只是看起來是這樣的),在這裡我很開心的輸入以下代碼:
content[i].split(日)[0]
本以為日期就這樣提取出來了,結果返回的竟然是原字元串!!難道是字打錯了,嘗試以下代碼:
日 in content[i]
竟然返回了False!也就是 日 並不在字元串 2017年1月1日XXXX 里!怎麼可能??我瞪大眼睛看了半天,一度懷疑我學的是假python。。。
懷疑歸懷疑,問題還是要解決。思索了下想到每個字其實都是對應一個編碼,看到的字只是電腦輸出的這個編碼對應的字元而已,比如Python默認的編碼是utf-8,於是我試了下:
content[i][8].encode(utf-8)日.encode(utf-8)
果然返回的結果不一樣,提取出來的日字編碼是bxe2xbdx87,而我自己輸入的日字編碼為bxe6x97xa5,看起來一個字編碼不一樣!!(如果有大神幫忙解惑為啥會這樣我將不勝感激。。)不信你可以度娘一個漢字與utf互轉的網頁,當你輸入日字時出現的是第二個編碼,而你用第一個和第二個編碼反查漢字的話,輸出的都是日字。
填坑過程我就不寫了,在通讀了這個庫的代碼後我發現想改只能從安裝過程入手(白讀半天源代碼了。。),這就是之前說不要pip安裝的原因。
接下來我貼下我的解決方案,如果有大神有其他方法還望分享。
這個庫在安裝時候需要單獨安裝對於cjk字元的支持,這個開發者在如何安裝部分也有講,比如macos/linux版命令如下:
python tools/conv_cmap.py pdfminer/cmap Adobe-CNS1 cmaprsrc/cid2code_Adobe_CNS1.txtpython tools/conv_cmap.py pdfminer/cmap Adobe-GB1 cmaprsrc/cid2code_Adobe_GB1.txt
這裡先不著急運行以上命令。因為我的PDF是UniGB-UCS2-H編碼,所以研究了一下cid2code_Adobe_GB1.txt,這個文件其實就是把GB系列的編碼映射成utf-8編碼。查了一下日字的編碼,果然對應著兩套utf-8編碼e2bd87,e697a5。到這裡問題基本已經摸清楚了,只要改腳本映射到第二個編碼問題就解決了。
接下來就簡單了,查看conv_cmap.py,發現這個腳本做了兩件事情:第一是輸出各種編碼轉CID的字典,第二是輸出CID轉utf-8字典。這裡只需要對第二步稍做改動,定位到文件中的以下位置:
hcodes = []vcodes = []
在這兩行下面加入以下代碼:
if len(x.split(,)) == 1: temp = x.split(,)else: temp = x.split(,)[1:]
這4行代碼的意思就是去掉我們輸入不了的那一套編碼,只留下能輸入的那一套。
改過以後再執行安裝:
python tools/conv_cmap.py pdfminer/cmap Adobe-CNS1 cmaprsrc/cid2code_Adobe_CNS1.txtpython tools/conv_cmap.py pdfminer/cmap Adobe-GB1 cmaprsrc/cid2code_Adobe_GB1.txtpython setup.py install
經過這樣的修改,安裝後提取的內容的編碼就與我們輸入的編碼一致了,問題解決!
如果有同學遇到其他編碼的相似問題,這個方法應該也能解決。如果不行可以貼出來大家一起研究~~
推薦閱讀:
※理解 Python 裝飾器看這一篇就夠了
※黃哥Python 出幾個題目大家練習
※9、續7--文章的編寫頁面(略)
※Python3 str在內存中的存儲方式?
※細數那些Python的Web框架