陸承佳
摘要:文章介紹了一個可用于自動分析、整理、導出工程圖數(shù)據(jù)的Python腳本。該腳本利用Python標準模塊os與第三方模塊pdfplumber及xlwt,遍歷目標路徑下所有PDF格式文件,并提取每張圖樣中的關鍵信息,最終統(tǒng)一導入一個Excel工作簿,進而幫助工程師節(jié)省大量手動查找和記錄所需的時間。
關鍵詞:Python;工程圖;PDF;Excel;數(shù)據(jù)分析
中圖分類號:TP311? ? ?文獻標識碼:A
文章編號:1009-3044(2019)18-0266-03
Abstract: In this paper, a Python script is written to analyze, dispose and export data of engineering drawings automatically. It uses the standard module os and third-party modules pdfplumber & xlwt to traverse all PDF documents in the target path, then extract core data of each drawing and finally import them into an Excel workbook. This script can help engineers save much time spent in manual searching and recording.
Key words: Python; Engineering Drawing; PDF; Excel; Data Analysis
1 背景
無論是在產(chǎn)品設計、制造還是使用環(huán)節(jié)中,工程圖都起到了至關重要的作用——設計者通過圖樣表達設計思想,制造者依據(jù)圖樣加工、檢驗、調試產(chǎn)品,使用者借助圖樣了解結構性能、運作參數(shù)等。
通過對比圖樣信息,工程師可以明確不同產(chǎn)品間的設計差異。但對于部分圖面復雜的工程圖,一些重要信息不易被直接找到。此外,當涉及圖樣較多時,工程師的核查分析工作將變得更為煩瑣。
文章旨在使用Python程序設計語言編寫一個自動化腳本,批量提取PDF工程圖內的關鍵數(shù)據(jù)并寫入Excel工作簿中,進而節(jié)省工程師手動查找和記錄圖樣信息所需的時間。
2 開發(fā)環(huán)境簡介
Python 是一門非常通用的高級語言[1]。自20世紀90年代初它誕生至今,Python憑借其簡潔性、易讀性以及可擴展性,已經(jīng)成為最受歡迎的程序設計語言之一。
Python不僅自帶有強大的標準庫,可以執(zhí)行系統(tǒng)管理、網(wǎng)絡通信、文本讀寫等操作。而且,Python社區(qū)提供了大量第三方模塊。它們功能極其豐富,覆蓋科學計算、網(wǎng)站開發(fā)、圖形系統(tǒng)等各種領域,并且大多成熟而穩(wěn)定。
文章以Python 3.7內置的集成開發(fā)環(huán)境IDLE為平臺編寫程序,通過遍歷某一文件夾內全部PDF格式圖樣,依次從中讀取所需信息,再統(tǒng)一寫入Excel工作簿內,最終實現(xiàn)工程圖數(shù)據(jù)自動批量分析、整理、導出功能。
3 主要算法思路
現(xiàn)假定有30張PDF格式的電機圖樣,工程師需要從中抽取并整理所有電機的圖號、供應商號、產(chǎn)地、電壓、功率、轉速等參數(shù),并存儲進一個Excel文檔內。
工程圖數(shù)據(jù)提取功能的Python腳本主函數(shù)如圖1所示。
該功能的實現(xiàn)大致可分為兩部分:PDF文檔讀取和Excel文檔寫入——分別對應示例代碼中的PDF()與Excel()子函數(shù)。而在調用PDF()函數(shù)前,首先應指明文件所在目錄路徑,再創(chuàng)建一個列表(list)用以儲存信息。接著,調用標準os模塊的listdir()函數(shù)獲取該文件夾的目錄內容。
隨后,對于其中全部PDF文檔,逐一將它們的文件名與文件夾路徑拼接,得到完整的文件路徑并作為PDF()函數(shù)的實參。值得注意的是,雖然Python的列表不必像C/C++的數(shù)組一樣預先定義元素個數(shù),但為了便于按照paramName列表順序存放所找到的數(shù)據(jù)以及優(yōu)化程序算法,在定義paramValue列表的同時為其賦予了7個“空格”元素。然后,調用PDF()函數(shù)從電機圖樣獲取參數(shù)并覆蓋paramValue初始元素后,將該列表加入paramTable(一個包含列表的列表)中。
最后,調用Excel()函數(shù)將paramTable二維列表內所有元素(即30臺電機的參數(shù))寫入一個Excel工作簿中。
4 PDF文檔
4.1 第三方模塊選取
目前,Python包管理工具pip已發(fā)布上千PDF文檔相關項目。文章針對三個常用以讀取PDF文本的模塊,就它們是否適于提取工程圖信息展開了對比研究:
首先,pdfminer3k作為PDFMiner 的Python 3移植版,既可通過命令行使用,又可整合到代碼中[2]。但其只能直接采集表格內字符串,而無法保留信息之間的位置關系,不利于工程師準確找到目標數(shù)據(jù)。
其次,tabula-java是用以讀取PDF表格數(shù)據(jù)的java庫,而tabula-py作為其python 的簡單封裝亦仍依賴于java7/8。此外,實測表明tabula-py對表格進行處理時,會出現(xiàn)信息識別錯誤、無法區(qū)分不同表格等問題。
最后,pdfplumber是按頁處理 PDF的模塊,其不僅能獲得頁面的全部文字,而且提供了專門的方法用于處理表格。盡管在實際應用中,pdfplumber讀取的數(shù)據(jù)依然存在一定瑕疵,但已明顯優(yōu)于pdfminer3k和tabula-py。
綜上所述,文章最終選取了pdfplumber模塊用以處理PDF工程圖。
4.2 表格參數(shù)讀取
使用pdfplumber模塊分析PDF文檔既可通過pdfplumber.Page類的.extract_text()方法將頁面內所有字符對象采集到一個字符串中,亦可調用.extract_words方法獲取每一個單詞及其圖面位置坐標并放入字典(dictionary)內。但鑒于電機參數(shù)大多被記錄在表格內,文章最終采用.extract_tables()方法根據(jù)圖面表格劃分將數(shù)據(jù)放入不同字符串——對于不在任何表格內的信息如注釋,同樣可被導出。
使用.extract_tables()方法直接返回的是頁面中全部表格的列表。該列表結構自上而下依次包括:單一表格(table)、行(row)以及格(cell)。因此,若要訪問工程圖內所有單元格必須經(jīng)歷4輪循環(huán)(算上主函數(shù)的文件遍歷則為5層循環(huán)),詳細代碼如圖2所示。
文章先通過字符串“DRAWING NO”(或“SHEET”)與“SITE”找到相關單元格,再調用split()函數(shù)將格內字符串分割成由若干子串組成的列表——由于未指定“分隔符”,split()將基于默認的空白字符:空格、換行符、制表符進行分割[1]。隨后,判斷每個列表是否為要求的信息——圖號應為字母和數(shù)字結合,且首項為D或X的字符串;而產(chǎn)地只有四種情況。雖然,這種執(zhí)行兩次判斷又增加了一次循環(huán)的算法對于一些簡單的工程圖顯得有些冗余,但也極大地降低了從復雜圖樣提取錯誤數(shù)據(jù)的可能性。
在程序找到包含頻率參數(shù)名(“HZ”或“FREQ”)的單元格后,將當前行(i)列(j)下第k行的單元格數(shù)據(jù)記入列表中——大部分情況下k等于1,即參數(shù)名之下一格就是其對應值。但對于如圖5的表格,因為參數(shù)名行右端有兩行,.extract_tables()方法在將表格轉換成列表時,在參數(shù)名與參數(shù)值間也增加了一行空元素,所以k的值為2。其他電氣參數(shù)的獲取方式亦類似,文章便不再贅述了。
4.3 注釋信息獲取
因為注釋同樣會被.extract_tables()導出,并放入某一“單元格”字符串中,所以為獲取注釋內的信息,可采用和標題欄圖號及產(chǎn)地相同的算法:先找到包含關鍵詞的字符串,再分析并從中抽取目標數(shù)據(jù)。然而與標題欄表格不同的是,存放注釋的字符串包含內容龐雜,除整段技術要求外,甚至還可能包括產(chǎn)品外形尺寸。因此,注釋信息的判斷、篩選邏輯亦必須更為“嚴苛”。
程序先從圖樣內找到包含供應商名或“供應商”(VENDOR)的單元格。其次,鑒于字符串中的句號并不是要求的內容,故將其替換為空格同時便于執(zhí)行下一步操作。然后,調用split()函數(shù)將字符串分割成列表。最后,抽取出符合供應商號命名規(guī)則的列表元素。
5 Excel文檔
5.1 第三方模塊介紹
Python目前常用以處理Excel工作簿的模塊包括xlrd,xlwt和xlutils。其中,xlrd只能讀取xls;xlwt只能在新建xls后寫入;xlutils能將xlrd.Book“復制”為xlwt.Workbook,從而獲取現(xiàn)有xls數(shù)據(jù)并在其基礎上進行寫入,最終將新文件轉存實現(xiàn)“修改”。
由于反復讀寫Excel文檔會大幅降低程序運行效率,文章采用了先將全部收集到的信息存儲在一個二維列表中,再將它們統(tǒng)一導入一個xls格式文件的算法,故只需引用xlwt模塊執(zhí)行單次寫入操作即可。
5.2 數(shù)據(jù)寫入
當完成文件夾目錄下所有工程圖的遍歷并將數(shù)據(jù)存入paramTable二維列表后,主函數(shù)調用Excel()子函數(shù)開始將該列表的元素錄入xls表格,具體代碼如圖8所示。
相比Excel軟件本身,通過xlwt模塊新建xls格式文件時,有必要在程序內“手動”設置一些參數(shù)。例如在創(chuàng)建“工作簿”(Workbook)的同時,文章指定了UTF-8 為“編碼方式”(encoding)——UTF-8 編碼簡單快速、字符覆蓋面廣、出錯率低,是Python、Linux 以及HTML 的標準文本編碼格式[1]。其次,通過Workbook類的.add_sheet()方法新建了一個“工作表”(Worksheet)。
接著,構建兩層循環(huán)并調用Worksheet類的.write()方法逐行、逐個將paramTable列表的子列及其元素寫入表內。
最后,將該工作簿命名為“Parameter.xls”并保存在和工程圖相同的目錄下。
5.3 結果分析
最終,30張PDF電機圖樣的關鍵信息由Python腳本批量提取并寫入Excel文檔后,如圖9所示。
然而,顯然表中有不少單元格空缺了,甚至記入了錯誤的內容。下面便逐一對這些問題產(chǎn)生的原因展開分析:
1) 第5張圖號為D159180P01的電機導出信息中缺失了產(chǎn)地,但其卻是包含在實際PDF文檔標題欄表格內的。將該圖所有信息打印出后得知,是.extract_tables()方法誤將同一單元格內的“TLR”分割為“TL”與“R”,并歸入了不同字符串中。同理,第16張圖D160171P01的頻率參數(shù)也被錯誤地填入了“0/50”(原圖中為“60/50”);
2) 第11、12張電機圖樣(D159878P01 & D159879P01)缺失了供應商號。經(jīng)查實,原PDF電機圖樣內確實未包含該信息;
3) 倒數(shù)第5、6臺電機(D965130P01 & D965128P01)的功率為小數(shù)。由于這兩張圖中的功率單位為“瓦”(W),而不是默認的“馬力”(HP)。因此經(jīng)過單位換算后,便得到了圖9所示數(shù)據(jù);
4) 最后4張工程圖的供應商號和產(chǎn)地,甚至整張圖紙信息都導出失敗了。因為,.extract_tables()方法只能讀取文本內容,而X13612048與X70660696的部分數(shù)據(jù)以圖片形式顯示在PDF文檔內,而剩下兩張工程圖則整頁均為圖片。
綜上所示,除了原圖樣信息不全與同類參數(shù)單位換算因素外,使用Python進行PDF文檔數(shù)據(jù)分析的主要問題包括:1、表格內容劃分錯誤;2、圖片信息難以讀取。對此,未來可能繼續(xù)嘗試其他方法或模塊,并對圖像識別技術展開研究。
6 結束語
文章介紹了基于Python編程語言的自動批量分析、整理、導出圖樣數(shù)據(jù)的功能。該功能利用Python標準模塊os與第三方模塊pdfplumber及xlwt,遍歷目標路徑下全部PDF格式文件,并提取每張工程圖中的關鍵信息,最終統(tǒng)一導入一個Excel工作簿。
盡管,使用Python腳本采集的數(shù)據(jù)存在些許不足,依然有賴工程師手動完善,但同時該腳本也成功獲取了大部分標準化圖樣的信息,從而幫助工程師省去了大量煩瑣重復的工作。
最后,無論是Python語言本身,還是其第三方模塊均仍在不斷發(fā)展壯大。相信隨著版本的更新迭代和功能的添加優(yōu)化,Python還將被應用于更多大型、復雜的項目開發(fā)。
參考文獻:
[1] Bill Lubanovic. Python語言及其應用[M]. 北京: 人民郵電出版社, 2016.
[2] Ryan Mitchell. Python網(wǎng)絡數(shù)據(jù)采集[M]. 北京: 人民郵電出版社, 2016.
【通聯(lián)編輯:謝媛媛】