0x00問題背景
前段時間在工作中遇到了一個需求,簡單介紹就是需要在過去6個月中某市每天不同蔬菜的菜價中查找公司所采購特定蔬菜對應(yīng)那天的價格,計算差值,看似簡單但數(shù)據(jù)量龐大,光錄入就花了不少時間,耗費(fèi)了大家不少精力,當(dāng)時想到用python解決這個問題,但是時間緊迫沒有認(rèn)真研究這幾個交互Excle的庫,依照當(dāng)時搜索的部分資料和自己親身的使用來看,主要有:
xlwt
xlrd
xlutils
xlwings
openpyxl
這幾個庫各有好處,也各有缺陷,綜合來看,上次直接使用了openpyxl是一個比較正確的選擇。
0x01python交互庫介紹
關(guān)于這幾個庫的介紹網(wǎng)上很多了,安裝也都非常簡單,可以按照pip install XXX的方式來安裝,我將在這次問題中遇到的幾個重要方面做記錄:
xlrd&&xlwt&&xlutils
- 首先搜到的就是兩個最簡單的庫xlwt和xlrd,兩個庫功能分開,一個負(fù)責(zé)讀另一個負(fù)責(zé)寫,但美中不足的就是只能支持對xls的寫,所以不滿足我們的使用需求,
import xlrd
import xlwt
from xlutils.copy import copy
book = xlrd.open_workbook() #打開一個表格文件,句柄傳給book
count = book.sheets()#獲取sheets對象,這時使用len()獲得sheet對象個數(shù)
count = book.nsheets #共有多少個sheet
獲取一個sheet有兩種方式,通過名字或通過編號,對應(yīng)方法為book.sheet_by_index(0)或book.sheet_by_name,獲得sheet對象后讀取特定單元格值cell_value(0,10),括號內(nèi)為行列值,均從0開始計。且同類型的單元格數(shù)值可以直接比較。
sheet1.nrows #獲取行數(shù),用來遍歷
xlwt創(chuàng)建一個新的工作表并對其進(jìn)行修改,雖然修改的功能強(qiáng)大,但不能對xlsx修改,也不能在已有的表中做修改,所以還是有很多的限制的。而使用了xlutils導(dǎo)入的copy方法復(fù)制一個新的表格再利用xlwt對其修改時,操作后發(fā)現(xiàn)生成的xlsx不可讀了,文件損壞,也饒了不少彎路。
xlwings
- 大家都說xlwings是最強(qiáng)大的excle交互庫,包含了讀寫的全部功能,使用也比較簡單,但是比起其他的庫來說,操作的方式好像有呢么一丟丟不同,同樣我們也了解一下打開文件、獲取sheet、獲取行數(shù)、獲取單元格值這幾個基本操作。
導(dǎo)入庫運(yùn)行后發(fā)現(xiàn)還需要依賴庫win32api
1.可以使用pip install pypiwin32解決問題
2.在https://sourceforge.net/projects/pywin32中下載對應(yīng)自己python版本的win32包。安裝前關(guān)閉占用python的進(jìn)程,一路next。
import xlwings
book = xlwings.Book(strName) #
sheet1 = book.sheets[0] #選擇一個sheet對象,編號為0
sheet2 = book.sheet('9.17') #選擇一個sheet對象,名稱為9.17
print sheet1[0,0].value #讀取0,0單元格的內(nèi)容以index形式索引
print sheet1.range('a1').value #以單元格名稱為索引讀取
讀取簡單,對應(yīng)的寫入也非常簡單
sheet1[0,0].value = "XXX"
sheet1.range('a1').value = "XXX"
獲取行列數(shù),用來遍歷
nrow = sheet1.api.UsedRange.Rows.count
ncol = sheet1.api.UsedRange.Columns.count
基本也只用到這些操作了,下面著重講講我所用的openpyxl。
openpyxl
這個庫是在實(shí)踐中所用的庫,使用簡單,功能強(qiáng)大,與xlwings很難比較孰強(qiáng)孰弱,都能滿足我們的時間需求。
import openpyxl
work = openpyxl.load_workbook('Test.xlsx') #打開一個工作簿
sheet_names = work.get_sheet_names() #獲得sheet_name的數(shù)組
sheet1 = work.get_sheet_by_name('9.99') #以sheet名稱獲取sheet對象
sheet2 = work.get_sheet_by_name(sheet_names[0]) #獲取名稱數(shù)組后按索引,可以在不知道名稱的情況下遍歷
print sheet1.cell(1,1).value #需要注意的是單元格從1,1開始,而不是0
sheet1.cell(1,1).value = '111' #寫單元格
print sheet1.max_row #總行數(shù)
print sheet1.max_column #總列數(shù)
work.save('001T_ok.xlsx')#保存更名
0x02問題分析
接觸這個任務(wù)時有這個想法是第一次將python運(yùn)用到實(shí)際,想要解放生產(chǎn)力,所以還是遇到了很多的小問題,記錄一下以備不時之需,整個實(shí)踐可以細(xì)化為幾個部分,這也是在遇到問題后的分析思路。
第一,操作方面:對需要修改表格的操作,包括打開,遍歷,讀寫,然后保存。
第二,邏輯方面:首先從第一項(xiàng)菜品開始,在本市對應(yīng)日期的所有菜品中查找,找到對應(yīng)價格,填寫上去;>其次是有名稱不統(tǒng)一的情況出現(xiàn),例如“大蔥”,“蔥”、“姜”,“生姜”等同類菜品的不同叫法。
第三,編碼方面:名稱均為漢字 ,分為打印輸出的編碼問題和日期比較的編碼問題。
第四,庫對文件格式的支持問題:選擇xlwings和openpyxl這兩個庫來完成實(shí)踐。
0x03代碼實(shí)現(xiàn)
細(xì)化為四個問題后開始代碼的實(shí)現(xiàn),操作方面上文已經(jīng)提到。
1.名稱不一致問題又建了一個名稱的更新表 Csql.xlsx,可以讓查找不到的菜品在新的xlsx中替換名字查詢,還可以隨時追加新的內(nèi)容,這時就再次遍歷表就可以了。
2.日期問題在每個錄入的表中做標(biāo)記,使用excle中內(nèi)容來互相比較,避免格式問題。
3.查詢不到的使用try跳過。
4.使用flag位標(biāo)記。
實(shí)現(xiàn)的代碼也很簡單,主要是記錄一下使用的庫和基本的操作。