海口網(wǎng)站建設(shè)運(yùn)營(yíng)百度手機(jī)端排名如何優(yōu)化
個(gè)人學(xué)習(xí)筆記,僅供參考。
需求:提取AUTOSAR SWS中所有的API接口信息,用于生成C代碼。
此處以AUTOSAR_SWS_CANDriver.pdf為例,若需要提取多個(gè)SWS文件,遍歷各個(gè)文件即可。
1.Python包
pdfplumber是一款完全用python開發(fā)的pdf解析庫(kù),對(duì)于線框完全的表格,pdfminer能給出比較好的抽取效果,但是對(duì)于線框不完全(包含無(wú)線框)的表格,其效果就差了不少。因?yàn)樵趯?shí)際項(xiàng)目所需處理的pdf文檔中,線框完全及不完全的表格都比較多。
備注:安裝時(shí),可能會(huì)因?yàn)榫W(wǎng)絡(luò)問(wèn)題,導(dǎo)致pdfplumber安裝失敗,可以切換國(guó)內(nèi)鏡像進(jìn)行安裝,具體命令如下:
pip install pdfplumber -i http://pypi.douban.com/simple
其他國(guó)內(nèi)源如下:
清華:https://pypi.tuna.tsinghua.edu.cn/simple
阿里云:http://mirrors.aliyun.com/pypi/simple/
中國(guó)科技大學(xué) https://pypi.mirrors.ustc.edu.cn/simple/
華中理工大學(xué):http://pypi.hustunique.com/
山東理工大學(xué):http://pypi.sdutlinux.org/
2.實(shí)現(xiàn)思路
目標(biāo)表格
具體步驟
1、使用extract_tables解析當(dāng)前page所有表格,判斷一個(gè)單元格為“Service Name”(關(guān)鍵字)
2、若存在Service Name,將此表格的內(nèi)容追加到總表
3、讀取當(dāng)前表的同時(shí)判斷是否是完整的表格,如果不是,則繼續(xù)讀取下一頁(yè),在一起追加到總表
備注:第一個(gè)單元格不是“Service Name”,存在兩種情況,一是非我們想要的表格,另一個(gè)是部分我們需要的,后者在步驟3中處理掉,所以無(wú)影響
參考代碼
import pdfplumberinputFile = "AUTOSAR_SWS_CANDriver.pdf"
functionList = []
# 前15頁(yè)無(wú)有效信息,為提高效率,減少掃描頁(yè)數(shù)
startPage = 15def readPdfFile():global functionListtable_settings = {"vertical_strategy": "lines", # 對(duì)于完整的表格,vertical_strategy與horizontal_strategy都配置為lines"horizontal_strategy": "lines","snap_y_tolerance": 10, # y方向上較短的線條extract_tables也會(huì)識(shí)別為表格的邊界,最后導(dǎo)致識(shí)別出錯(cuò)# 這里將最小像素點(diǎn)設(shè)置為10(小于10丟棄線條丟棄)}with pdfplumber.open(inputFile) as pdf:######################################### 僅前期調(diào)試使用,具體使用時(shí),可以屏蔽first_page = pdf.pages[63] # 指定(63+1)頁(yè)P(yáng)DF內(nèi)容im = first_page.to_image() # 轉(zhuǎn)換為image個(gè)數(shù)im.reset().debug_tablefinder(table_settings) # 將table_settings配置效果輸出到圖片方便觀看im.save('xx.PNG', format="PNG", quantize=True, colors=256, bits=8)########################################for j in range(len(pdf.pages) - startPage):page = pdf.pages[j + startPage]table = page.extract_tables(table_settings)for i in range(len(table)): # 遍歷所有表格row = table[i]if row[0][0] == 'Service Name': # 找表頭tempList = row # 先復(fù)制已有的信息if (i == (len(table)-1)) and (row[-1][0] != 'Available via'): # 最后一個(gè)表,且缺少最后一行,繼續(xù)讀取下一頁(yè)的第一個(gè)表page1 = pdf.pages[j + startPage + 1] # 繼續(xù)讀取下一頁(yè)table1 = page1.extract_tables(table_settings)for table1_1 in table1[0]: # 只需要讀取第一個(gè)表格(其他的會(huì)在在下次循環(huán)中寫入)if table1_1[0] == '': # 如果第一個(gè)表格的第一個(gè)參數(shù)為空,代表第一行的參數(shù)的補(bǔ)充,并不是新的參數(shù),所以此處拼接上去tempList[-1][1] += '\n' + table1_1[1]else: # 如果不為空,代表是新參數(shù),直接追加即可tempList.append(table1_1)functionList.append(tempList) # 最后匯總到總表格內(nèi)if __name__ == '__main__':readPdfFile()for i in functionList:print(i)print('共%d個(gè)函數(shù)' % len(functionList))
3.輸出結(jié)果
最終保存到全局列表functionList中,后續(xù)可根據(jù)各自的開發(fā)規(guī)范/要求輸出相應(yīng)的代碼。
4. 配置說(shuō)明
table_settings = {"vertical_strategy": "lines", # 對(duì)于完整的表格,vertical_strategy與horizontal_strategy都配置為lines"horizontal_strategy": "lines","snap_y_tolerance": 10, # y方向上較短的線條extract_tables也會(huì)識(shí)別為表格的邊界,最后導(dǎo)致識(shí)別出錯(cuò)# 這里將最小像素點(diǎn)設(shè)置為10(小于10丟棄線條丟棄)}
4.1 snap_y_tolerance默認(rèn)值效果
這里可以發(fā)現(xiàn)識(shí)別了很多無(wú)效的邊界進(jìn)入,導(dǎo)致組成了很多多余的單元格,最終識(shí)別出錯(cuò),或者無(wú)法識(shí)別
備注:四個(gè)正交連接的小圓圈框起來(lái)的區(qū)域認(rèn)為是一個(gè)單元格,此處不是很明顯,具體可以看下圖
4.2 snap_y_tolerance配置為10效果
可以很明顯看見,上面很多短的邊界被忽略掉了。
備注:“Syntax”出個(gè)人了解不應(yīng)該識(shí)別出來(lái),但是此處任然識(shí)別出來(lái)了,可能因?yàn)樽髠?cè)的兩點(diǎn)未連接,所以不影響最終結(jié)果,此處未進(jìn)行深入研究,知道的小伙伴,歡迎討論
5. 參考資料
1、https://zhuanlan.zhihu.com/p/352722932
2、https://github.com/jsvine/pdfplumber#visual-debugging
3、https://github.com/jsvine/pdfplumber/blob/stable/examples/notebooks/extract-table-nics.ipynb
4、https://zhuanlan.zhihu.com/p/100460222
5、https://zhuanlan.zhihu.com/p/100462752
6、https://zhuanlan.zhihu.com/p/100464246