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