使用python處理excel文檔

在這一小節(jié)躬充,我們將會(huì)學(xué)習(xí)如何使用Python來(lái)操作Excel文檔以及如何利用Python語(yǔ)言的函數(shù)和表達(dá)式操縱Excel文檔中的數(shù)據(jù)耻讽。雖然微軟公司本身提供了一些函數(shù)寸宏,我們可以使用這些函數(shù)操作Excel文檔颓遏。但是铸董,使用Excel自帶的函數(shù)受限于Excel軟件的功能限制易结。換句話說檀轨,只有微軟提供了某種功能蹬耘,我們才能使用相應(yīng)的功能解決問題剥啤。如果微軟沒有提供相應(yīng)的函數(shù)應(yīng)對(duì)一個(gè)復(fù)雜的功能锦溪,那么,我們只能進(jìn)行重復(fù)性操作府怯。使用Python語(yǔ)言操作Excel則不然刻诊,我們可以靈活應(yīng)用Python語(yǔ)言的所有功能,讀取牺丙、計(jì)算和編輯Excel文檔中的數(shù)據(jù)则涯。

除了使用Python語(yǔ)言操作Excel文檔以外,讀者還可以使用VBA操作Excel文檔冲簿。VBA(Visual Basic for Applications)是Visual Basic的一種宏語(yǔ)言粟判,是微軟開發(fā)出來(lái)在其桌面應(yīng)用程序中執(zhí)行自動(dòng)化任務(wù)的編程語(yǔ)言,主要用來(lái)擴(kuò)展Windows應(yīng)用程序(特別是Microsoft Office軟件)的功能峦剔。靈活應(yīng)用VBA這門宏語(yǔ)言能夠在處理文檔時(shí)顯著提高工作效率浮入,但是,VBA代碼可讀性差羊异、應(yīng)用領(lǐng)域有限事秀。而Python語(yǔ)言擁有文檔豐富、語(yǔ)法清晰野舶、易于學(xué)習(xí)易迹、跨平臺(tái)等諸多優(yōu)點(diǎn)。因此平道,筆者強(qiáng)烈建議使用Python語(yǔ)言來(lái)處理Excel文檔睹欲,不要浪費(fèi)時(shí)間學(xué)習(xí)VBA。

7.1.1 openpyxl簡(jiǎn)介與安裝

根據(jù)官方文檔的介紹,openpyxl是一個(gè)讀寫Excel 2010(xlsx/xlsm)文檔的Python庫(kù)窘疮,如果要處理更早格式的Excel文檔袋哼,需要用到另外的庫(kù)。openpyxl是一個(gè)比較綜合的工具闸衫,能夠同時(shí)讀取和修改Excel文檔涛贯。XlsxWriter也是一個(gè)與Excel處理相關(guān)的知名項(xiàng)目,僅支持創(chuàng)建和寫入Excel文檔蔚出,不支持讀取Excel文檔弟翘。

openpyxl是一個(gè)開源項(xiàng)目,因此骄酗,在使用之前需要先進(jìn)行安裝:

pip install openpyxl

7.1.2 使用openpyxl讀取Excel文檔

在使用openpyxl操作Excel文檔之前稀余,我們簡(jiǎn)單回顧一下Excel文檔,幫助我們理解openpyxl對(duì)Excel文檔的抽象趋翻。一個(gè)Excel文檔稱為一個(gè)工作簿睛琳,在Office 2010下,典型工作簿的文件擴(kuò)展名為xlsx踏烙。一個(gè)工作簿可以包含多個(gè)表格(在Excel又稱為sheet)师骗。打開工作簿后會(huì)默認(rèn)顯示一個(gè)表格,這個(gè)表格一般稱為活躍表宙帝。表格中包含若干單元格丧凤,所有單元格都有一個(gè)唯一的坐標(biāo)募闲。Excel通過行和列表示一個(gè)單元格步脓,其中,行的坐標(biāo)使用數(shù)字表示浩螺,列的坐標(biāo)使用字母表示靴患。例如,表格中左上角的單元格要出,其坐標(biāo)為“A1”鸳君,該單元格下方的單元格坐標(biāo)為“A2”,右邊的單元格坐標(biāo)為“B1”患蹂。

理解了Excel的構(gòu)成以后或颊,再來(lái)看openpyxl對(duì)Excel的抽象就會(huì)覺得很好理解。openxpyxl中有三個(gè)不同層次的類传于,分別是Workbook囱挑、Worksheet和Cell。Workbook是對(duì)Excel工作簿的抽象沼溜,Worksheet是對(duì)表格的抽象平挑,Cell是對(duì)單元格的抽象。每一個(gè)類都包含了若干屬性和方法,以便于我們通過這些屬性和方法獲取表格中的數(shù)據(jù)通熄。

例如唆涝,我們要打開一個(gè)Excel表格或者創(chuàng)建一個(gè)Excel文檔,都需要?jiǎng)?chuàng)建一個(gè)Workbook對(duì)象唇辨。我們需要獲取Excel文檔中的某一張表廊酣,應(yīng)該先創(chuàng)建一個(gè)Workbook對(duì)象,然后使用該對(duì)象的方法來(lái)得到一個(gè)Worksheet對(duì)象助泽。如果要讀取或者修改某個(gè)單元格啰扛,我們需要先獲得Worksheet對(duì)象,然后再獲取代表單元格的Cell對(duì)象嗡贺。

在接下來(lái)的例子中隐解,我們將使用下面的Excel文檔(見圖7-1)進(jìn)行實(shí)驗(yàn)。讀者可以在本書的附件中找到該文檔诫睬,文檔的名稱為example.xlsx煞茫。

openpyxl模塊使用到的Excel文檔

一個(gè)Workbook對(duì)象代表一個(gè)Excel文檔,因此摄凡,在操作一個(gè)Excel之前续徽,應(yīng)該先創(chuàng)建一個(gè)Workbook對(duì)象。對(duì)于創(chuàng)建一個(gè)新的Excel文檔亲澡,直接進(jìn)行Workbook類調(diào)用即可钦扭。對(duì)于讀取一個(gè)已有的Excel文檔,可以使用openpyxl模塊的load_workbook函數(shù)床绪。該函數(shù)接受多個(gè)參數(shù)客情,但只有filename參數(shù)為必傳參數(shù)。filenmame可以是一個(gè)文件名癞己,也可以是一個(gè)打開的文件對(duì)象膀斋。如下所示:

import openpyxl
wb = openpyxl.load_workbook('example.xlsx')

調(diào)用完load_workbook函數(shù)以后,我們就得到了一個(gè)Workbook對(duì)象痹雅。Workbook對(duì)象有很多的屬性和方法仰担,其中,大部分方法都與sheet相關(guān)绩社。Workbook對(duì)象的部分屬性如下:

?active:獲取活躍的Worksheet摔蓝;
?read_only:是否以read_only模式打開Excel文檔;
?encoding:文檔的字符集編碼愉耙;
?properties:文檔的元數(shù)據(jù)贮尉,如標(biāo)題,創(chuàng)建者劲阎,創(chuàng)建日期等绘盟;
?worksheets:以列表的形式返回所有的Worksheet。

下面是我們附件中example.xlsx文件的屬性,包括活躍的Worksheet龄毡、只讀屬性和字符集編碼吠卷。如下所示:

>>>wb.active
<Worksheet "student">

>>>wb.read_only
False

>>>wb.encoding
'utf-8'

>>>wb.worksheets
[<Worksheet "student">, <Worksheet "teacher">]

Workbook對(duì)象的方法大都與Worksheet相關(guān)。常用的方法如下:

?get_sheet_names:獲取所有表格的名稱沦零;
?get_sheet_by_name:通過表格名稱獲取Worksheet對(duì)象祭隔;
?get_active_sheet:獲取活躍的表格;
?remove_sheet:刪除一個(gè)表格路操;
?create_sheet:創(chuàng)建一個(gè)空的表格疾渴;
?copy_worksheet:在Workbook內(nèi)拷貝表格。

附件的example.xlsx文件中包含了兩個(gè)表格屯仗。其中搞坝,名為teacher的表格為活躍表格。如下所示:

>>>wb.get_sheet_names()
[u'student', u'teacher']
# 上面函數(shù)新版本以后不再使用魁袜,將使用如下wb.sheetnames 獲取sheetnames
>>>wb.sheetnames
[u'student', u'teacher']

>>>wb.get_active_sheet() # 建議使用新版wb.active
<Worksheet "teacher">

>>> wb.get_sheet_by_name(u'student') # 建議使用新版 wb['student']
<Worksheet "student">

有了Worksheet對(duì)象以后桩撮,我們可以通過這個(gè)Worksheet對(duì)象獲取表格的屬性,得到單元格中的數(shù)據(jù)峰弹,修改表格中的內(nèi)容店量。openpyxl提供了非常靈活的方式來(lái)訪問表格中的單元格和數(shù)據(jù)。常用的Worksheet屬性如下:

?title:表格的標(biāo)題鞠呈;
?dimensions表格的大小融师,這里的大小是指有含有數(shù)據(jù)的表格大小。例如蚁吝,對(duì)于example.xlsx文件旱爆,dimensions屬性的值為'A1:E11';
?max_row表格的最大行灭将;
?min_row表格的最小行疼鸟;
?max_column表格的最大列后控;
?min_column表格的最小列庙曙;
?rows按行獲取單元格(Cell對(duì)象);
?columns按列獲取單元格(Cell對(duì)象)浩淘;
?freeze_panes凍結(jié)窗格捌朴;
?values按行獲取表格的內(nèi)容(數(shù)據(jù))。

對(duì)于附件中的example.xlsx文件张抄,其擁有的屬性如下所示:

>>>ws = wb.get_sheet_by_name('student')
>>>ws.title
u'student'

>>>ws.dimensions
'A1:E11'

>>>ws.max_column
5

>>>ws.min_column
1

>>>ws.max_row
11

>>>ws.min_row
1

>>>ws.columns
<generator object _cells_by_col at 0x7fe5a4d89640>

>>>ws.rows
<generator object _cells_by_row at 0x7fe5a5d32550>

>>>ws.values
<generator object values at 0x7fe5ac289780>

在這段代碼中砂蔽,我們首先通過Workbook的get_sheet_by_name方法獲取Worksheet對(duì)象。接著署惯,通過不同的屬性名獲取student這張表的屬性左驾。其中,columns、rows和values這幾個(gè)屬性都是通過生成器(生成器以后介紹)的方式返回?cái)?shù)據(jù)诡右。openpyxl并不知道我們的表格中有多少數(shù)據(jù)安岂,在數(shù)據(jù)量大的情況下,如果一次獲取所有數(shù)據(jù)帆吻,勢(shì)必會(huì)占用較多的內(nèi)存域那。因此,openpyxl的設(shè)計(jì)中猜煮,需要返回?cái)?shù)據(jù)時(shí)都是通過生成器的方式返回次员。對(duì)于附件中的student表,因?yàn)橛涗涊^少王带,我們可以使用list函數(shù)或tuple函數(shù)獲取所有的數(shù)值淑蔚。需要注意的是,columns與rows返回的是Cell對(duì)象愕撰,values返回的是數(shù)據(jù)束倍。

freeze_panes這個(gè)參數(shù)比較特別,主要用于在表格較大時(shí)凍結(jié)頂部的行或左邊的列盟戏。對(duì)于凍結(jié)的行或列绪妹,就算用戶滾動(dòng)電子表格,也是始終可見的柿究。每個(gè)Worksheet對(duì)象都有一個(gè)freeze_panes屬性邮旷,可以設(shè)置為一個(gè)Cell對(duì)象或一個(gè)單元格坐標(biāo)的字符串,單元格上面的行和左邊的列將會(huì)凍結(jié)(注意單元格所在的行和列并不會(huì)凍結(jié))蝇摸。例如婶肩,我們需要凍結(jié)第一行,那么freeze_panes取值應(yīng)該為A2貌夕,如果要凍結(jié)第一列律歼,freeze_panes取值為B1。如果要同時(shí)凍結(jié)第一行和第一列啡专,則freeze_panes取值為B2险毁。freeze_panes取值為None表示不凍結(jié)任何窗格。

下面是Worksheet常用的一些方法:

?iter_rows:按行獲取所有單元格(Cell對(duì)象)们童;
?iter_cols:按列獲取所有的單元格畔况;
?append:在表格末尾添加數(shù)據(jù);
?merged_cells:合并多個(gè)單元格慧库;
?unmerge_cells:移除合并的單元格跷跪。

iter_rows方法和iter_cols方法在參數(shù)取默認(rèn)值時(shí),與rows屬性和columns屬性的作用相同齐板。區(qū)別在于吵瞻,iter_rows方法和iter_cols方法可以通過函數(shù)參數(shù)限定訪問表格的范圍葛菇。如下所示:

>>>list(ws.iter_rows(min_row=2, max_row=4, min_col=1, max_col=3))
[(<Cell u'student'.A2>, <Cell u'student'.B2>, <Cell u'student'.C2>),
(<Cell u'student'.A3>, <Cell u'student'.B3>, <Cell u'student'.C3>),
(<Cell u'student'.A4>, <Cell u'student'.B4>, <Cell u'student'.C4>)]

從Worksheet的屬性和方法的使用中可以看到,很多屬性和方法返回的不是某一個(gè)具體的數(shù)值橡羞,而是一個(gè)Cell對(duì)象熟呛。一個(gè)Cell對(duì)象就代表一個(gè)單元格,我們可以直接使用Excel坐標(biāo)的方式獲取Cell對(duì)象尉姨,也可以使用Worksheet的cell方法獲取Cell對(duì)象庵朝。如下所示:

>>> ws['A1']
<Cell u'student'.A1>

>>>ws['A2']
<Cell u'student'.A2>

>>>ws.cell(row=1, column=2)
<Cell u'student'.B1>

>>>ws.cell(row=2, column=1)
<Cell u'student'.A2>

# 也可以只讀一列數(shù)據(jù):
>>>ws['B']
# 只讀一行數(shù)據(jù):
>>>ws[83]

Cell對(duì)象比較簡(jiǎn)單,其常用的屬性如下:

?row:?jiǎn)卧袼诘男校?br> ?column:?jiǎn)卧袼诘牧校?br> ?value:?jiǎn)卧竦娜≈担?br> ?cordinate:?jiǎn)卧竦淖鴺?biāo)又厉。

為了熟悉openpyxl提供的各種API九府,接下來(lái)我們使用4種不同的方法來(lái)打印student表中的內(nèi)容。為了對(duì)數(shù)據(jù)的格式進(jìn)行控制覆致,我們使用print函數(shù)而不是print語(yǔ)句進(jìn)行打印侄旬。

下面是通過Worksheet的values方法打印表格中的數(shù)據(jù),這也是打印數(shù)據(jù)最簡(jiǎn)單的方法煌妈。values通過生成器訪問數(shù)據(jù)并按行返回儡羔,因此,我們使用for循環(huán)遍歷表格的內(nèi)容璧诵。

>>>from __future__ import print_function

>>>for row in ws.values:
...:      print(*row)
image.png

我們也可以使用Worksheet的rows屬性來(lái)遍歷表格中的數(shù)據(jù)汰蜘。rows屬性按行返回Cell對(duì)象,因此之宿,我們使用列表推導(dǎo)來(lái)獲取每一個(gè)Cell對(duì)象的值族操。如下所示:

>>>for row in ws.rows:

...:      print(*[cell.value for cell in row])
image.png

Worksheet的iter_rows方法在不加任何參數(shù)的情況下,與rows屬性效果相同比被,因此色难,這種方法與前一種方法看起來(lái)很像。

>>>for row in ws.iter_rows():

...:      print(*[cell.value for cell in row])
image.png

最后這種方式是最麻煩的方式等缀,也是大家最容易想到的方式枷莉。我們首先獲取表格的最小行數(shù)和最大行數(shù),然后獲取最小列數(shù)與最大列數(shù)尺迂,通過行和列的索引確定一個(gè)唯一單元格笤妙。確定單元格以后,打印單元格的值枪狂。這種方式是每確定一個(gè)單元格打印一次危喉,因此宋渔,我們?cè)趐rint函數(shù)中將end參數(shù)取值為空格來(lái)避免換行州疾,并在內(nèi)層for循環(huán)結(jié)束以后,顯示地進(jìn)行換行皇拣。如下所示:

>>>for i in range(ws.min_row, ws.max_row + 1):
...:      for j in range(ws.min_column, ws.max_column + 1):
...:           print(ws.cell(row=i, column=j).value, end=' ')
...:      print()

7.1.3 使用openpyxl修改Excel文檔

openpyxl不但可以讀取Excel文檔严蓖,而且還可以修改Excel文檔薄嫡,包括修改單元格的數(shù)據(jù)、合并單元格颗胡、修改單元格的字體毫深、在Excel文檔中畫圖等。我們接下來(lái)將介紹如何使用openpyxl創(chuàng)建工作簿毒姨,創(chuàng)建和刪除表格哑蔫,修改單元格的數(shù)據(jù)。然后弧呐,我們通過計(jì)算example.xlsx文件中每位同學(xué)的平均分來(lái)演示如何修改一份Excel文檔闸迷。

一個(gè)Workbook對(duì)象就代表了一個(gè)工作簿,因此俘枫,新建一個(gè)工作簿就是創(chuàng)建一個(gè)Workbook對(duì)象腥沽。創(chuàng)建完Workbook對(duì)象以后,默認(rèn)會(huì)有一個(gè)名為“sheet1”的表格鸠蚪,我們可以通過表格的名稱或get_active_sheet方法來(lái)獲取這個(gè)表格今阳。獲取表格以后,可以通過給表格的title屬性賦值的方式來(lái)修改表格的名稱茅信。

In [1]: from openpyxl import Workbook
In [2]: wb = Workbook()
In [3]: wb.get_sheet_names()
Out[3]: [u'Sheet']
In [4]: ws = wb.get_active_sheet()
In [5]: ws.title
Out[5]: u'Sheet'
In [6]: ws.title = 'student'
In [7]: ws.title
Out[7]: u'student'

創(chuàng)建完Workbook以后盾舌,就可以使用create_sheet方法創(chuàng)建新的表格,也可以使用remove_sheet方法刪除表格蘸鲸。如下所示:

In [8]: wb.create_sheet(index=0, title="new sheet")
Out[8]: <Worksheet "new sheet">
In [9]: wb.get_sheet_names()
Out[9]: [u'new sheet', u'student']
In [10]: wb.remove_sheet(wb.get_sheet_by_name('student'))
In [11]: wb.get_sheet_names()
Out[11]: [u'new sheet']
In [12]: ws = wb.get_active_sheet()
In [13]: ws.title
Out[13]: u'new sheet'

如果要填充單元格的數(shù)據(jù)矿筝,可以直接對(duì)單元格賦值。openpyxl還能夠自動(dòng)處理Python數(shù)據(jù)類型到Excel數(shù)據(jù)類型之間的轉(zhuǎn)換棚贾。如下所示:

In [14]: ws['A1'] = 'Hello, world'
In [15]: import datetime
In [16]: ws['A2'] = datetime.datetime.now()

我們已經(jīng)創(chuàng)建了工作簿窖维,同時(shí)在工作簿中創(chuàng)建了表格,并為表格中的部分單元格進(jìn)行了賦值妙痹。此時(shí)铸史,磁盤上還沒有一個(gè)Excel文檔保存了這些信息,我們需要調(diào)用Workbook的save方法將數(shù)據(jù)保存到磁盤中怯伊。如下所示:

In [17]: wb.save('sample.xlsx')

下面來(lái)看一個(gè)案例琳轿,用來(lái)鞏固openpyxl讀取和修改Excel文檔的知識(shí)。附件里的example.xlsx文件保存了十位學(xué)生的信息耿芹,其中崭篡,最后三列分別是學(xué)生的語(yǔ)文、英語(yǔ)和數(shù)學(xué)成績(jī)“娠酰現(xiàn)在琉闪,我們希望計(jì)算每一位學(xué)生的平均分和總分,并保存到表格的右側(cè)中砸彬。

為了計(jì)算學(xué)生的成績(jī)颠毙,我們首先需要打開Excel文檔斯入,并創(chuàng)建一個(gè)Workbook對(duì)象。有了Workbook對(duì)象以后蛀蜜,通過表格的名稱獲取我們需要操作的表格刻两。在我們下面的代碼中,將表格傳遞給process_worksheet函數(shù)滴某。在process_worksheet函數(shù)中磅摹,我們首先獲取了表格的最大列,用來(lái)確定平均分與總分的列坐標(biāo)霎奢。隨后偏瓤,我們需要使用Worksheet的ifer_rows方法遍歷每一位學(xué)生的成績(jī),iter_rows方法支持指定遍歷的起點(diǎn)和終點(diǎn)椰憋。在我們的表格中厅克,第一行保存的是表頭信息,不需要計(jì)算橙依。因此证舟,我們通過傳遞min_row為2表示從第二行開始遍歷。表格的第一列保存的是學(xué)生的學(xué)號(hào)窗骑,第二列保存的是學(xué)生的姓名女责,這也是我們?cè)谟?jì)算平均分和總分時(shí)不會(huì)使用的數(shù)據(jù)。因此创译,我們通過傳遞min_col為3表示從第三列開始遍歷抵知。iter_rows函數(shù)按行返回單元格,因此软族,我們只需要循環(huán)遍歷iter_rows函數(shù)的結(jié)果刷喜,就實(shí)現(xiàn)了計(jì)算每一位學(xué)生的平均分和總分的功能。需要注意的是立砸,iter_rows函數(shù)返回的是Cell對(duì)象掖疮,所以,我們?cè)谟?jì)算成績(jī)之前需要先通過一個(gè)列表推導(dǎo)表達(dá)式颗祝,得到每一個(gè)單元格的取值浊闪。隨后計(jì)算平均分和總分,并且通過每一行的第一個(gè)單元格獲取平均分和總分的行坐標(biāo)螺戳。有了行坐標(biāo)和列坐標(biāo)以后搁宾,直接通過Worksheet對(duì)象的cell方法為單元格復(fù)制。這就實(shí)現(xiàn)了計(jì)算平均分和總分倔幼,并且保存到表格右側(cè)的功能盖腿。

process_worksheet函數(shù)處理完畢以后,當(dāng)前所做的修改都還在內(nèi)存之中凤藏,我們需要調(diào)用Workbook的save方法將Workbook所表示的工作簿保存到磁盤文件中奸忽。如下所示:

#! /usr/bin/python
#-*- coding: UTF-8 -*-
import openpyxl

def process_worksheet(sheet):
    avg_column = sheet.max_column + 1
    sum_column = sheet.max_column + 2
    for row in sheet.iter_rows(min_row=2, min_col=3):
        scores = [cell.value for cell in row]
        sum_score = sum(scores)
        avg_score = sum_score / len(scores)
          # 計(jì)算平均分和總分堕伪,并且保存到最后兩列
        sheet.cell(row=row[0].row, column=avg_column).value = avg_score
        sheet.cell(row=row[0].row, column=sum_column).value = sum_score
    # 設(shè)置平均分和總分的標(biāo)題部分
    sheet.cell(row=1, column=avg_column).value = 'avg'
    sheet.cell(row=1, column=sum_column).value = 'sum'

def main():
    wb = openpyxl.load_workbook('example.xlsx')
    sheet = wb.get_sheet_by_name('student')
    process_worksheet(sheet)
    wb.save('example_copy.xlsx')
if __name__ == '__main__':
    main()

修改完成以后揖庄,當(dāng)前目錄下存在一個(gè)名為example_copy.xlsx的文件栗菜,該文件的內(nèi)容相對(duì)于附件中的example.xlsx文件增加了兩列,分別是學(xué)生的平均分和總分蹄梢,如圖7-2所示疙筹。

image.png

圖7-2 計(jì)算平均分和總分以后的結(jié)果

7.1.4 案例:合并多個(gè)Excel文檔到一個(gè)Excel文檔

我們也可以使用Excel的函數(shù)實(shí)現(xiàn)計(jì)算學(xué)生平均分和總分的例子,而且更加簡(jiǎn)單快捷禁炒。如果說計(jì)算平均分和總分的例子達(dá)到的是事倍功半的效果而咆,那么,接下來(lái)這個(gè)例子將實(shí)現(xiàn)事半功倍幕袱!

現(xiàn)在暴备,假設(shè)你是公司的人力資源管理部人才發(fā)展中心的員工,需要組織公司2019年的技術(shù)分享们豌。因此涯捻,你需要將一個(gè)類似于圖7-3的報(bào)名表格發(fā)送給公司的各位同事,讓公司的同事自行填寫望迎。填寫完成以后障癌,你需要將每一位同事返回的Excel文檔進(jìn)行合并。需要注意的是辩尊,部分同事可能填寫多行涛浙。同事們填寫完畢以后,會(huì)將報(bào)名表再發(fā)送給你摄欲。你收到了每位同事的報(bào)名表后轿亮,接下來(lái)要做的是,將這些報(bào)名表合并到一張匯總表中胸墙。

圖7-3 技術(shù)分享報(bào)名表

將多個(gè)Excel文檔合并成單個(gè)文件哀托,表面上看是個(gè)簡(jiǎn)單的需求。但是劳秋,因?yàn)槲覀兊臄?shù)據(jù)在不同的Excel文檔中仓手,即便是熟練的Excel操作人員也沒有辦法快速進(jìn)行處理。這個(gè)時(shí)候玻淑,只能依次打開各個(gè)文檔嗽冒,并將內(nèi)容手動(dòng)拷貝到匯總表中。對(duì)于有編程背景的技術(shù)人員补履,我們不可能允許這么低效率的重復(fù)工作添坊。這個(gè)時(shí)候就顯現(xiàn)出使用Python語(yǔ)言處理Excel的優(yōu)勢(shì)。

對(duì)于這里的需求箫锤,使用Python語(yǔ)言處理將會(huì)非常簡(jiǎn)單贬蛙。如下所示:

#! /usr/bin/python
import os
import glob
import openpyxl

def merge_xlsx_files(xlsx_files):
    wb = openpyxl.load_workbook(xlsx_files[0])
    ws = wb.active
    ws.title = "merged result"
    for filename in xlsx_files[1:]:
        workbook = openpyxl.load_workbook(filename)
        sheet = workbook.active
        for row in sheet.iter_rows(min_row=2):
            values = [cell.value for cell in row]
            ws.append(values)
    return wb

def get_all_xlsx_files(path):
    xlsx_files = glob.glob(os.path.join(path, '*.xlsx'))
    sorted(xlsx_files, key=str.lower)
    return xlsx_files

def main():
    xlsx_files = get_all_xlsx_files(os.path.expanduser('~lmx'))
    wb = merge_xlsx_files(xlsx_files)
    wb.save('merged_form.xlsx')

if __name__ == '__main__':
    main()

在這個(gè)例子中雨女,我們首先通過glob獲取了指定目錄下所有的Excel文檔。然后阳准,我們將這些文檔按照文件名稱進(jìn)行了排序氛堕。排序以后,在merge_xlsx_files函數(shù)中嘗試合并多個(gè)Excel文檔野蝇。我們合并Excel的思路也很簡(jiǎn)單:

1)獲取第一個(gè)文檔中的表格(我們的Excel文檔中只有一個(gè)表格);
2)依次遍歷其他文件中的報(bào)名表讼稚,并通過iter_rows函數(shù)忽略報(bào)名表中的首行內(nèi)容;
3)通過列表推導(dǎo)獲取報(bào)名表中的數(shù)據(jù)绕沈,然后調(diào)用Worksheet的append函數(shù)將數(shù)據(jù)添加到匯總表的末尾锐想。

上述操作完成以后,返回Workbook對(duì)象乍狐。在main函數(shù)中赠摇,我們調(diào)用Workbook的save方法將匯總表保存到merged_form.xlsx文件中。

我們只花費(fèi)幾分鐘時(shí)間編寫了不到30行的Python代碼浅蚪,就實(shí)現(xiàn)了將多個(gè)Excel文檔合并成單個(gè)文件的功能藕帜。因?yàn)槭荘ython程序進(jìn)行處理,所以無(wú)論有多少?gòu)埍硇枰喜⒍寄軌蚩焖偬幚砭虮桑⑶也粫?huì)出錯(cuò)耘戚,也不會(huì)抱怨處理的表格太多。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末操漠,一起剝皮案震驚了整個(gè)濱河市收津,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌浊伙,老刑警劉巖撞秋,帶你破解...
    沈念sama閱讀 221,635評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異嚣鄙,居然都是意外死亡吻贿,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,543評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門哑子,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)舅列,“玉大人,你說我怎么就攤上這事卧蜓≌室” “怎么了?”我有些...
    開封第一講書人閱讀 168,083評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵弥奸,是天一觀的道長(zhǎng)榨惠。 經(jīng)常有香客問我,道長(zhǎng),這世上最難降的妖魔是什么赠橙? 我笑而不...
    開封第一講書人閱讀 59,640評(píng)論 1 296
  • 正文 為了忘掉前任耽装,我火速辦了婚禮,結(jié)果婚禮上期揪,老公的妹妹穿的比我還像新娘掉奄。我一直安慰自己,他們只是感情好横侦,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,640評(píng)論 6 397
  • 文/花漫 我一把揭開白布挥萌。 她就那樣靜靜地躺著绰姻,像睡著了一般枉侧。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上狂芋,一...
    開封第一講書人閱讀 52,262評(píng)論 1 308
  • 那天榨馁,我揣著相機(jī)與錄音,去河邊找鬼帜矾。 笑死翼虫,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的屡萤。 我是一名探鬼主播珍剑,決...
    沈念sama閱讀 40,833評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼死陆!你這毒婦竟也來(lái)了招拙?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,736評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤措译,失蹤者是張志新(化名)和其女友劉穎别凤,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體领虹,經(jīng)...
    沈念sama閱讀 46,280評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡规哪,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,369評(píng)論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了塌衰。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片诉稍。...
    茶點(diǎn)故事閱讀 40,503評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖最疆,靈堂內(nèi)的尸體忽然破棺而出杯巨,到底是詐尸還是另有隱情,我是刑警寧澤肚菠,帶...
    沈念sama閱讀 36,185評(píng)論 5 350
  • 正文 年R本政府宣布舔箭,位于F島的核電站矾端,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏夕膀。R本人自食惡果不足惜都办,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,870評(píng)論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望镜会。 院中可真熱鬧檬寂,春花似錦、人聲如沸戳表。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,340評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)匾旭。三九已至镣屹,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間价涝,已是汗流浹背女蜈。 一陣腳步聲響...
    開封第一講書人閱讀 33,460評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留色瘩,地道東北人伪窖。 一個(gè)月前我還...
    沈念sama閱讀 48,909評(píng)論 3 376
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像居兆,于是被迫代替她去往敵國(guó)和親覆山。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,512評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容