python處理excel文件有很多方法,最開始接觸的是xlrd、xlsxwriter模塊,分別用於excel文件的讀、寫。后來又學習了openpyxl模塊,可以同時完成excel文件的讀、寫。再后來,接觸了大牛pandas,這是python中專門用於數據分析的模塊,有更加強大的功能。
本文嘗試梳理一下這幾個方法,以實際案例來對比各種方法的優劣。
1. xlrd、xlsxwriter模塊

1 import xlrd #讀取excel文件 2 import xlsxwriter #寫入excel文件 3 file_name = r'C:/2020/python-exer/excel_doc/time_fmt.xls' #存在一個excel文件,用於讀 4 file_name1 = r'C:/2020/python-exer/excel_doc/time_fmt_output.xls' #新建一個excel文件,用於寫 5 # 讀取excel文件,按行讀取數據,每行數據對應一個列表元素 6 def excel_lines(): 7 wb = xlrd.open_workbook(file_name) 8 # 打開Excel文件 9 sheet1 = wb.sheet_by_name('Sheet1') # 通過excel表格sheet名稱獲取工作表 10 dat = [] # 創建空list 11 Max_lines = sheet1.nrows # sheet1數據最大行數,即便每列元素不同。 12 print(Max_lines) 13 for a in range(Max_lines): 14 cells = sheet1.row_values(a) # 每行數據賦值給cells 15 dat.append(cells) 16 return dat
#>>>[['序號', '時間格式定義'], [1.0, '%a Locale’s abbreviated weekday name. '],
[2.0, '%A Locale’s full weekday name. '],
……
從輸出內容看出,得到的是一個嵌套list,每行數據對應着一個list元素。
# 讀取excel文件,按列讀取數據,每列數據對應一個列表元素

1 def excel_cols(): 2 wb = xlrd.open_workbook(file_name) 3 # 1 打開Excel文件,按照名字獲取第一個工作表 4 # sheet1 = wb.sheet_by_name('Sheet1') # 通過excel表格sheet名稱獲取工作表 5 # 2 Excel的所有sheet是個列表,通過索引獲取第一個工作表 6 sheet1 = wb.sheets()[0] 7 # 3 通過索引獲取第一個工作表,這種方法有明顯優勢,不需要知道excel的sheet名稱。與#3方法相同 8 # 最大的優勢能用for循環,遍歷所有的sheet。 9 # sheet1 = wb.sheet_by_index(0) 10 # sheet_2= wb.sheets()[1] 11 # print(sheet_2.col_values(0)) 12 13 dat = [] # 創建空list 14 global Max_rows 15 Max_cols = sheet1.ncols # sheet1數據最大列數 16 Max_rows = sheet1.nrows # sheet1數據最大行數 17 print("Max_rows:", Max_rows) 18 print("Max_cols:", Max_cols) 19 for a in range(Max_cols): 20 cells = sheet1.col_values(a) # 每列數據賦值給cells 21 dat.append(cells) # 每列數據追加到列表dat,那么dat就是以列數據為元素的列表 22 return dat
#>>> [['序號', 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 19.0,
20.0, 21.0, 22.0, 23.0, 24.0, '', ''], ['時間格式定義', '%a Locale’s abbreviated weekday name. ', ……
從上面的輸出結果看,按照excel文件的列讀取數據,生成嵌套list,每一列對應一個list元素
#寫入excel文件,新建sheet用於保存數據

1 def write_excel(): 2 a = excel_cols() 3 excel_cols = [] # 保存列值的列表 4 excel_cols_comment = [] # 保存列注釋的列表 5 6 for i in range(Max_rows): 7 if i == 0: 8 # square_col.append(a[1][0]) #專門取列的頭,實際上為了方便以后的數據處理。 9 print("列的名字:", a[1][0]) 10 else: 11 excel_cols.append(a[1][i][:3]) #:2只取該元素的前2位,去掉后面的注釋。 12 excel_cols_comment.append(a[1][i][5:]) # 上面列的注釋,取字符串5: 13 14 print("獲取格式化time參數: \n", excel_cols) 15 print("獲取time參數的說明: \n", excel_cols_comment) 16 17 workbook_w = xlsxwriter.Workbook(file_name1) 18 sheet2 = workbook_w.add_worksheet("output_sheet") 19 for i in range(Max_rows): # 因列名單獨處理了,所以真正的列元素數要比總數-1 20 # strf_time = time.strftime(excel_cols[i]) # 調用時間模塊函數,參數為每列的值 21 # comment = excel_cols_comment[i] 22 if i == 0: # 每個列的第一行,列名。i代表行號,如果是很多列,也可以再增加j循環,表示列號 23 sheet2.write(i, 0, f"格式化時間參數:time.strftime") 24 sheet2.write(i, 1, f"執行結果") 25 sheet2.write(i, 2, f"注釋") 26 else: # 每個列,從第二行開始循環寫入 27 ##下面的i-1,原因在於i是人為的把列頭編寫輸出。而對於列表元素來說,索引從0開始。 28 strf_time = time.strftime(excel_cols[i - 1]) # 調用時間模塊函數,參數為每列的值 29 comment = excel_cols_comment[i - 1] 30 sheet2.write(i, 0, f"({repr(excel_cols[i - 1])})") 31 # 注意這里的i-1,前面的i與excel表格相關,后面的i-1是因為列的元素還是從0開始。 32 33 sheet2.write(i, 1, f"{strf_time}") 34 sheet2.write(i, 2, f"{comment}") 35 print("寫入成功") 36 workbook_w.close()
以上的程序,實際的關鍵點在於sheet.write函數的參數處理,第一個參數是行,第二個參數是列,第三個參數是寫入的數據。其他的語句都是針對數據的具體化處理。
2.openpyxl模塊,既可以讀、也可以寫
import openpyxl
from openpyxl import load_workbook
# 1.載入已存在的Excel
filename = r'C:\2020\python-exer\excel_doc\test.xlsx'
wb = load_workbook(filename)
# 注意load_workbook只能打開已經存在的Excel,不能創建新的工作簿
# 2.根據名稱獲取工作表
# Workbook對象屬性(工作簿操作)
# sheetnames:獲取工作簿中的表(列表)
# active:獲取當前活躍的Worksheet
# worksheets:以列表的形式返回所有的Worksheet(表格)
# read_only:判斷是否以read_only模式打開Excel文檔
# encoding:獲取文檔的字符集編碼
# properties:獲取文檔的元數據,如標題,創建者,創建日期等

1 def get_properties(): ##獲取excel的sheet屬性函數 2 print(wb.sheetnames) # >>>['Sheet1', '2表單12'] 3 print(wb.active) # >>><Worksheet "2表單12"> 4 print(wb.worksheets) # >>>[<Worksheet "Sheet1">, <Worksheet "2表單12">] 5 print(wb.read_only) # >>>False 6 print(wb.encoding) # >>>utf-8 7 print(wb.properties) # 獲取文檔的元數據,如標題,創建者,創建日期等 8 print(wb.properties.creator, wb.properties.title) # >>>openpyxl None 9 wb.properties.title = 'test-openpyxl' # >>>修改屬性中的title 10 print(wb.properties.title) 11 print(wb.properties) # 確實修改了titile。 12 # 3.Worksheet,Cell對象(工作表操作,單元格)。獲取execl的sheet一般信息的函數 13 def get_sheet_info(): 14 global sheet 15 sheet = wb['Sheet1'] 16 # 獲取工作表的名稱 17 print(sheet.title) # >>>Sheet1 18 # 獲取工作表中行和列的最值 19 print(sheet.max_column) # >>>2 20 print(sheet.max_row) # >>>27 21 print(sheet.min_column) # >>>1 22 print(sheet.min_row) # >>>1 23 ##修改表的名稱 24 sheet.title = '時間參數' 25 print(sheet.title) # >>>時間參數 26 # 返回指定行指定列的單元格信息 27 print(sheet.cell(row=1, column=2).value) # >>>時間格式定義 28 cell = sheet['B1'] 29 print(cell) # >>><Cell '時間參數'.B1>。注意cell是對象,下面是具體的屬性: 30 print(cell.row, cell.column, cell.value, cell.coordinate) 31 # >>>1 2 時間格式定義 B1 32 # sheet的屬性,sheet是一個類: 33 print("sheet:", sheet, type(sheet)) 34 # 4.訪問單元格的所有信息,rows是sheet的一個屬性。該sheet的所有行信息。 35 def get_sheet_rows(): 36 print(sheet.rows) ##是一個生成器 37 ##<generator object Worksheet._cells_by_row at 0x000001806C22D820> 38 for row in sheet.rows: 39 # 循環遍歷每一個單元格 40 for cell in row: 41 # 獲取單元格的內容 42 print(cell.value, end=',') 43 print()
#>>>
序號,時間格式定義,
1,%a Locale’s abbreviated weekday name. ,
2,%A Locale’s full weekday name. ,
3,%b Locale’s abbreviated month name. ,
4,%B Locale’s full month name. ,……
通過以上輸出,按照excel的每行輸出內容。
#5openpyxl寫入excel

1 def save_to_excel(data, wbname, sheetname='Sheet1'): 2 """ 3 將以下信息保存到excel表中; 4 [[' BOOK', 50, 3], ['APPLE', 100, 1], ['BANANA', 200, 0.5]] 5 """ 6 print("寫入Excel[%s]中......." % (wbname)) 7 # 打開excel表, 如果文件不存在, 自己實例化一個WorkBook對象 8 wb = openpyxl.Workbook() 9 # 獲取當前工作表 10 sheet = wb.active 11 # 修改工作表的名稱 12 sheet.title = sheetname 13 14 data.insert(0,head_line) #重新插入表頭。 15 for row, item in enumerate(data): # 0 [' BOOK', 50, 3] 16 ##使用枚舉函數的好處,不用求元素總數len了。 17 for column, cellValue in enumerate(item): # 0 ' BOOK' 18 sheet.cell(row=row + 1, column=column + 1, value=cellValue) 19 20 # ** 往單元格寫入內容 21 # sheet.cell['B1'].value = "value" 22 # sheet.cell(row=1, column=2, value="value") 23 24 # 保存寫入的信息 25 wb.save(filename=wbname) 26 print("寫入成功!")
小結:通過對xlrd、xlswriter及openpyxl的應用案例,本質上都是把excel當做一個數據文件進行讀寫。只不過openpyxl既能讀又能寫罷了。而pandas是把excel當做
數據塊或者說是矩陣來處理。如同處理csv一樣,讀入的數據認為是dataframe,可以有更多的數據分析功能。
3.pandas對excel文件的處理,可以同時寫入多個sheet數據。

1 import pandas as pd 2 from pandas import DataFrame 3 filename = r'C:\2020\python-exer\excel_doc\pandas_excel.xlsx' 4 write_filename = r'C:\2020\python-exer\excel_doc\pandas_excel_1.xlsx' 5 csv_file=r'C:\2020\python-exer\excel_doc\pandas_excel_1.csv' 6 def pandas_write_excel(): 7 # 創建新的Excel文件。如果是已有的Excel文件,見下面的read函數。 8 # 准備字典數據,之所以引入list_dict[],為了實現同一個excel表同時寫入多個sheet(可以是不同數據)。 9 # 字典的鍵會被當做列索引。行索引自動增加1個序號數字列。如果是1個嵌套列表,DF會自動加上序號行作為列的索引。也會增加序號列作為行的索引。 10 list_dict = [] 11 dict1 = {'標題列1': ['張三', '李四'], 12 '標題列2': [80, 90], 13 '標題列3': [30, 40], 14 '標題列4': [50, 70], 15 } 16 dict2 = {'姓名': ['張三', '李四', '王五'], 17 '數學': [80, 90, 70], 18 '語文': [30, 40, 89], 19 '英語': [50, 70, 76], 20 } 21 22 for i in range(5): 23 list_dict.append(dict1) # 生成1個大列表,每個元素都是1個dict。 24 # df = DataFrame(dict1) 25 # print(df) 26 '''#>>>在原始數據前面加入序號列。 27 標題列1 標題列2 標題列3 標題列4 28 0 張三 80 30 50 29 1 李四 90 40 70 30 ''' 31 ##1pandas的df就是一個數據矩陣,天生與excel同構。所以可以直接寫入excel: 32 # df.to_excel(filename, index=False) ##只寫入1個sheet,不需要save、close。 33 writer = pd.ExcelWriter(filename) 34 ##2 如果需要同時寫入多個sheet,引入writer。而#1只是寫入一個sheet。 35 for i in range(4): 36 df = DataFrame(list_dict[i]) 37 df.to_excel(excel_writer=writer, sheet_name=f"班級{i}", index=False) 38 df = DataFrame(dict2) 39 # DataFrame可以把dict轉變為寫入的格式,如果index=True增加了第一列序號。如果index為False寫入的excel沒有序號 40 print(df) 41 df.to_excel(excel_writer=writer, sheet_name="高級班", index=True) 42 # 按列寫入字典,index為True,寫入的excel有序號。 43 writer.save() 44 # writer.close() #這個比較奇葩,打開excel根本無法寫入。關閉狀態下這條語句會有警告。到底是否需要關閉? 45 print('寫入成功!') 46 # 寫入單個sheet函數,當打開一個文件的時候,如果有多個sheet,用這個函數只保留1個sheet。 47 # 如果想同時寫入多個sheet用前面的函數。 48 def write_sheet(write_filename, Sheet_data, Sheet_name): 49 with pd.ExcelWriter(write_filename) as writer: 50 df = DataFrame(Sheet_data) 51 # #這里data是一個列表,而之前的函數是寫入字典,所以會有問題。而且data並不完全是原始數據。增加了序號列。 52 df.to_excel(excel_writer=writer, sheet_name=Sheet_name, index=False) 53 # index為False不寫入序號。否則,寫入序號。 54 writer.save() 55 print('寫入成功!')
下面比較一下讀寫excel文件和csv文件的異同:

1 def write_read_csv(data): 2 ##csv文件的寫入、讀取。感覺比excel簡單,至少沒有多個sheet的情況。 3 #而且,csv文件打開的時候也是可以進行寫操作的。而Excel文件不可以。 4 data_df = DataFrame(data) 5 # print(data_df) 6 data_df.to_csv(csv_file,index=False) 7 #index=False,不寫序號列。 8 print("寫入csv成功") 9 data=pd.read_csv(csv_file) 10 print("讀取csv文件數據:\n",data) 11 #讀出的結果與上面讀取excel一致,原始數據前面加上了序號列。 12 print("讀取csv成功")
小結:對於pandas來說,有了DataFrame,寫入Excel和寫入CSV可以根據需求可以同時進行,只是對應pandas模塊不同的讀寫函數而已。
總結上述,對於python來說,處理excel文件有很多的方法,但感覺pandas方法是更方便的,更接近數據處理,有更豐富的處理技巧。而其他模塊都是取出excel的行或者列數據,
再依照python的語言功能對這些數據進行進一步處理。