陸承佳



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