
作者:星安果?
來源:AirPython
上一篇python辦公自動化之Excel(上)文章中,我們聊到使用?xlrd、xlwt、xlutils 這一組合操作Excel 的方法。本篇文章將繼續(xù)聊另外一種方式,即:openpyxl。
不得不說,openpyxl 更強大!它支持?xlsx?格式的表格文件,并且支持 Numpy、Pandas 等包,可用于繪制圖表。
準(zhǔn)備:首先,我們需要安裝依賴包。
#?安裝依賴包 pip3?install?openpyxl
讀取數(shù)據(jù):使用 openpyxl 中的?load_workbook(filepath)?加載本地一個 Excel 文件,返回結(jié)果是一個工作簿對象。
import?openpyxl #?加載本地的Excel文件 wb?=?openpyxl.load_workbook(file_path)
利用工作簿對象,可以獲取所有的 Sheet 名稱及 Sheet 列表。
def?get_all_sheet_names(wb): ????""" ????獲取所有sheet的名稱 ????:param?wb: ????:return: ????""" ????#?sheet名稱列表 ????sheet_names?=?wb.sheetnames ????return?sheet_names def?get_all_sheet(wb): ????""" ????獲取所有的sheet ????:param?wb: ????:return: ????""" ????#?sheet名稱列表 ????sheet_names?=?get_all_sheet_names(wb) ????#?所有sheet ????sheets?=?[] ????for?sheet_name?in?sheet_names: ????????sheet?=?wb[sheet_name] ????????sheets.append(sheet) ????return?sheets
工作簿對象提供了?active?屬性,用于快速獲取當(dāng)前選擇的 Sheet。
def?get_current_sheet(wb): ????""" ????獲取當(dāng)前選擇的sheet,默認(rèn)是最后一個sheet ????:param?wb: ????:return: ????""" ????#?當(dāng)前選中的sheet ????current_sheet?=?wb.active ????return?current_sheet
另外,也可以通過?Sheet 名稱去獲取某一個特定的 Sheet 對象。
def?get_sheet_by_name(wb,?sheet_name): ????""" ????通過sheetname去查找某一個sheet ????:param?wb: ????:param?sheet_name: ????:return: ????""" ????sheet_names?=?get_all_sheet_names(wb) ????if?sheet_name?in?sheet_names: ????????result?=?wb[sheet_name] ????else: ????????result?=?None ????return?result
使用?sheet.max_row?和?sheet.max_column?可以獲取當(dāng)前 Sheet 中的數(shù)據(jù)行數(shù)和列數(shù)。
def?get_row_and_column_num(sheet): ????""" ????獲取sheet的行數(shù)和列數(shù) ????:param?sheet: ????:return: ????""" ????#?行數(shù) ????row_count?=?sheet.max_row ????#?列數(shù) ????column_count?=?sheet.max_column ????return?row_count,?column_count #?行數(shù)和列數(shù) row_count,?column_count?=?get_row_and_column_num(sheet) print('行數(shù)和列數(shù)分別為:',?row_count,?column_count)
openpyxl 提供 2 種方式來定位一個單元格,分別是:
并且,openpyxl.utils?提供了方法,便于?列索引?在兩者之間進(jìn)行轉(zhuǎn)換。
from?openpyxl.utils?import?get_column_letter,?column_index_from_string def?column_num_to_str(num): ????""" ????Excel索引列從數(shù)字轉(zhuǎn)為字母 ????:param?num: ????:return: ????""" ????return?get_column_letter(num) def?column_str_to_num(str): ????""" ????Excel索引列,從字母轉(zhuǎn)為數(shù)字 ????:param?str: ????:return: ????""" ????return?column_index_from_string(str)
單元格的獲取,同樣可以通過上面 2 種索引方式來獲取。
def?get_cell(sheet,?row_index,?column_index): ????""" ????獲取單元格 ????:param?sheet: ????:param?row_index: ????:param?column_index: ????:return: ????""" ????#?openpyxl索引都是從1開始計數(shù),這與xlrd有所不同 ????#?獲取某一個單元格(二選一) ????#?比如:獲取A1單元格的數(shù)據(jù),即第一個行、第一列的數(shù)據(jù) ????#?cell_one?=?sheet['A1'] ????cell_one?=?sheet.cell(row=row_index,?column=column_index) ????return?cell_one
在日常處理 Excel 數(shù)據(jù)過程中,可能需要判斷單元格數(shù)據(jù)類型,而 openpyxl 并沒有提供現(xiàn)成的方法。這里,我們可以通過單元格對象的?value?屬性拿到值,接著使用?isinstance?方法判斷數(shù)據(jù)類型。
def?get_cell_value_and_type(cell): ????""" ????獲取某一個cell的內(nèi)容及數(shù)據(jù)類型 ????:param?cell: ????:return: ????""" ????#?單元格的值 ????cell_value?=?cell.value ????#?單元格的類型 ????cell_type?=?get_cell_value_type(cell_value) ????return?cell_value,?cell_type def?get_cell_value_type(cell_value): ????""" ????獲取數(shù)據(jù)類型 ????:param?cell_value: ????:return: ????""" ????#?其中 ????#?0:空 ????# 1:數(shù)字 ????# 2:字符串 ????# 3:日期 ????# 4:其他 ????if?not?cell_value: ????????cell_type?=?0 ????elif?isinstance(cell_value,?int)?or?isinstance(cell_value,?float): ????????cell_type?=?1 ????elif?isinstance(cell_value,?str): ????????cell_type?=?2 ????elif?isinstance(cell_value,?datetime.datetime): ????????cell_type?=?3 ????else: ????????cell_type?=?4 ????return?cell_type=
單獨獲取某一行[列]的數(shù)據(jù),可以使用下面的方式:
def?get_row_cells_by_index(sheet,?row_index): ????""" ????通過行索引,獲取某一行的單元格 ????:param?row_index: ????:return: ????""" ????#?注意:第一列從1開始 ????row_cells?=?sheet[row_index] ????return?row_cells def?get_column_cells_by_index(sheet,?column_index): ????""" ????通過列索引,獲取某一列的單元格 ????""" ????#?數(shù)字轉(zhuǎn)為字母 ????column_index_str?=?column_num_to_str(column_index) ????#?獲取某一列的數(shù)據(jù) ????column_cells?=?sheet[column_index_str] ????return?column_cells
需要注意的是,獲取某一行的數(shù)據(jù)需要傳入數(shù)字索引;而對于列數(shù)據(jù)的獲取,必須傳入字符串索引。和 Python 列表范圍取值類似,openpyxl 同樣支持使用 : 符號拿到某個范圍內(nèi)的數(shù)據(jù)行[列]
def?get_rows_by_range(sheet,?row_index_start,?row_index_end): ????""" ????通過范圍去選擇行范圍 ????比如:選擇第2行到第4行的所有數(shù)據(jù),返回值為元組 ????:param?sheet: ????:param?row_index_start: ????:param?row_index_end: ????:return: ????""" ????rows_range?=?sheet[row_index_start:row_index_end] ????return?rows_range def?get_columns_by_range(sheet,?column_index_start,?column_index_end): ????""" ????通過范圍去選擇列范圍 ????比如:選擇第2列到第4列的所有數(shù)據(jù),返回值為元組 ????:param?sheet: ????:param?column_index_start: ????:param?column_index_end: ????:return: ????""" ????columns_range?=?sheet[column_num_to_str(column_index_start):column_num_to_str(column_index_end)] ????return?columns_range
寫入數(shù)據(jù)
要寫入數(shù)據(jù)到 Excel 表格。首先,使用?openpyxl.Workbook()?創(chuàng)建一個 Excel 工作簿對象。接著,使用工作簿對象的?create_sheet()?新建一個 Sheet。
#?創(chuàng)建一個Excel工作簿 #?注意:每次新建一個Excel文件,都會默認(rèn)生成一個名稱為【Sheet】的工作表Sheet wb?=?openpyxl.Workbook() #?創(chuàng)建一個新的sheet,默認(rèn)被插到尾部 #?new_sheet?=?wb.create_sheet('新的Sheet') #?也可以通過第二個參數(shù):index來指定插入的位置 #?比如:插入到開頭 new_sheet?=?wb.create_sheet('新的Sheet',?0)
默認(rèn)創(chuàng)建的 Sheet 被插入到最后一個位置,第 2 個參數(shù)可以指定 Sheet 插入的位置。
Sheet 標(biāo)簽的背景色同樣支持修改,使用?sheet_properties.tabColor?指定?RGB 顏色值。
比如,要設(shè)置某一個 Sheet 的背景色為紅色,只需要先查詢到對應(yīng)的?Sheet,然后指定顏色值為 FF0000 即可。
def?set_sheet_bg_color(sheet,?rgb_value): ????""" ????設(shè)置Sheet標(biāo)簽的顏色 ????:param?rgb_value: ????:return: ????""" ????#?設(shè)置Sheet底部按鈕的顏色(RRGGBB) ????sheet.sheet_properties.tabColor?=?rgb_value ?#?設(shè)置Sheet的背景色(紅色) set_sheet_bg_color(new_sheet,?'FF0000')
openpyxl?支持行列數(shù)字索引、字符串索引以這 2 種方式寫入數(shù)據(jù)到單元格中。
def?write_value_to_cell_with_num(sheet,?row_index,?column_index,?value): ????""" ????按行索引、列索引寫入數(shù)據(jù) ????:param?shell: ????:param?row_index:?行索引 ????:param?column_index:?列索引 ????:param?value: ????:return: ????""" ????#?二選一 ????sheet.cell(row=row_index,?column=column_index,?value=value) ????#?shell.cell(row=row_index,?column=column_index).value?=?value def?write_value_to_cell_with_index_str(sheet,?index_str,?value): ????""" ????按字母位置,寫入數(shù)據(jù)到對應(yīng)單元格 ????:param?shell: ????:param?index_str:?字母對應(yīng)的單元格位置 ????:param?value: ????:return: ????""" ????sheet[index_str]?=?value
在單元格中插入圖片也很簡單,openpyxl 提供的?add_image()?方法。參數(shù)有 2 個,分別是:圖片對象、單元格字符串索引。為了便于使用,我們可以將列索引進(jìn)行轉(zhuǎn)換,然后封裝成兩個插入圖片的方法。
from?openpyxl.drawing.image?import?Image def?insert_img_to_cell_with_num(sheet,?image_path,?row_index,?column_index): ????""" ????往單元格中插入圖片 ????:param?sheet: ????:param?image_path: ????:param?row_index: ????:param?column_index: ????:return: ????""" ????#?通過行索引、列索引,獲取到字母索引 ????index_str?=?column_num_to_str(column_index)?+?str(row_index) ????insert_img_to_cell_with_str(sheet,?image_path,?index_str) def?insert_img_to_cell_with_str(sheet,?image_path,?index_str): ????""" ????往單元格中插入圖片 ????:param?sheet: ????:param?image_path: ????:param?index_str: ????:return: ????""" ????sheet.add_image((image_path),?index_str)
最后,調(diào)用工作簿對象的?save()?方法,將數(shù)據(jù)真實寫入到 Excel 文件中。
#?注意:必須要寫入,才能真實的保存到文件中 wb.template?=?False wb.save('new.xlsx')
修改數(shù)據(jù)
修改數(shù)據(jù)包含:單元格數(shù)據(jù)的修改、單元格樣式的修改。對于單元格數(shù)據(jù)的修改,只需要先讀取工作簿對象,查詢到要操作的 Sheet 對象,然后調(diào)用上面的方法修改單元格數(shù)據(jù),最后調(diào)用 save() 函數(shù)保存覆蓋即可。
def?modify_excel(self,?file_path): ????""" ????修改本地Excel文件中數(shù)據(jù) ????:param?file_path: ????:return: ????""" ????#?讀取本地Excel文件 ????wb?=?openpyxl.load_workbook(file_path) ????#?讀取某一個sheet ????sheet?=?wb['第一個Sheet'] ????print(sheet) ????#?直接修改某一個單元格的數(shù)據(jù) ????write_value_to_cell_with_num(sheet,?1,?1,?'姓名1') ????#?保存并覆蓋 ????wb.save(file_path)
單元格樣式包含:字體樣式、單元格背景樣式、邊框樣式、對齊方式等。以常見的字體樣式、對齊方式為例。
首先,使用?openpyxl 中的?Font?類創(chuàng)建一個對象,指定字體名稱、字體大小、是否加粗、是否斜體、顏色、下劃線等。
from?openpyxl.styles?import?Font #?字體格式 #?指定字體類型、大小、是否加粗、顏色等 font0?=?Font(name='Calibri', ?????????????size=20, ?????????????bold=False, ?????????????italic=False, ?????????????vertAlign=None,?? ?????????????underline='none',? ?????????????strike=False, ?????????????color='FF00FF00')
接著,構(gòu)建一個?Alignment?對象,指定單元格的對齊方式。
from?openpyxl.styles?import?Font,Alignment #?單元格對齊方式 alignment0?=?Alignment(horizontal='center', ???????????????????????vertical='bottom', ???????????????????????text_rotation=0, ???????????????????????wrap_text=False, ???????????????????????shrink_to_fit=False, ???????????????????????indent=0)
最后,使用單元格對象的?font/alignment 屬性,將字體樣式和對齊方式設(shè)置進(jìn)去即可。
#?設(shè)置屬性樣式(字體、對齊方式) sheet['A1'].font?=?font0 sheet['A1'].alignment?=?alignment0
6. 進(jìn)階用法
接下來,聊聊幾個常用的進(jìn)階用法:
1、獲取可見及隱藏的 Sheet
通過判斷 Sheet 對象的?sheet_state?屬性值,可以判斷當(dāng)前 Sheet 是顯示還是隱藏。當(dāng)值為?visible?時,代表 Sheet 是顯示的。當(dāng)值是?hidden?時,代表這個 Sheet 被隱藏了。
def?get_all_visiable_sheets(wb): ????""" ????獲取工作簿中所有可見的sheet ????:param?wb: ????:return: ????""" ????return?[sheet?for?sheet?in?get_all_sheet(wb)?if?sheet.sheet_state?==?'visible'] def?get_all_hidden_sheets(wb): ????""" ????獲取工作簿中所有隱藏的sheet ????:param?wb: ????:return: ????""" ????return?[sheet?for?sheet?in?get_all_sheet(wb)?if?sheet.sheet_state?==?'hidden']
受限于篇幅,這里以獲取所有顯示/隱藏的行索引列表為例,遍歷 Sheet 對象的?row_dimensions?屬性值,通過判斷行屬性的?hidden?值,判斷當(dāng)前行是否隱藏或顯示。
def?get_all_rows_index(sheet,?hidden_or_visiable): ????""" ????獲取所有隱藏/顯示的行 ????:param?hidden_or_visiable:??True:隱藏;False:顯示 ????:param?sheet: ????:return: ????""" ????#?遍歷行 ????#?隱藏的索引 ????hidden_indexs?=?[] ????#?所有隱藏的行索引 ????for?row_index,?rowDimension?in?sheet.row_dimensions.items(): ????????if?rowDimension.hidden: ????????????hidden_indexs.append(row_index) ????#?所有顯示的行索引 ????visiable_indexs?=?[index?+?1?for?index?in?range(get_row_and_column_num(sheet) [0])?if?index?+?1?not?in?hidden_indexs] ????#?隱藏或者顯示的行索引列表 ????return?hidden_indexs?if?hidden_or_visiable?else?visiable_indexs、
3、獲取單元格字體顏色及單元格背景顏色
單元格對象的?font.color.rgb、fill.fgColor.rgb?屬性值分別代表字體顏色值、單元格背景顏色。
def?get_cell_font_color(sheet,?row_index,?column_index): ????""" ????獲取單元格字體的顏色 ????:param?sheet: ????:param?row_index:行索引 ????:param?column_index:列索引 ????:return: ????""" ????cell_color?=?sheet.cell(row_index,?column_index).font.color ????if?cell_color: ????????return?sheet.cell(row_index,?column_index).font.color.rgb ????else: ????????#?顏色不存在,可能單元格沒有數(shù)據(jù) ????????return?None def?get_cell_bg_color(sheet,?row_index,?column_index): ????""" ????獲取單元格背景的顏色 ????:param?sheet: ????:param?row_index:行索引 ????:param?column_index:列索引 ????:return: ????""" ????return?sheet.cell(row_index,?column_index).fill.fgColor.rgb
?最后
可以發(fā)現(xiàn),openpyxl 相比 xlrd/xlwt,提供了大量實用的 API,功能更強大,并且完美支持 xlsx!
——熱門課程推薦:
想從事業(yè)務(wù)型數(shù)據(jù)分析師,您可以點擊>>>“數(shù)據(jù)分析師”了解課程詳情;
想從事大數(shù)據(jù)分析師,您可以點擊>>>“大數(shù)據(jù)就業(yè)”了解課程詳情;
想成為人工智能工程師,您可以點擊>>>“人工智能就業(yè)”了解課程詳情;
想了解Python數(shù)據(jù)分析,您可以點擊>>>“Python數(shù)據(jù)分析師”了解課程詳情;
想咨詢互聯(lián)網(wǎng)運營,你可以點擊>>>“互聯(lián)網(wǎng)運營就業(yè)班”了解課程詳情;
數(shù)據(jù)分析咨詢請掃描二維碼
若不方便掃碼,搜微信號:CDAshujufenxi
SQL Server 中 CONVERT 函數(shù)的日期轉(zhuǎn)換:從基礎(chǔ)用法到實戰(zhàn)優(yōu)化 在 SQL Server 的數(shù)據(jù)處理中,日期格式轉(zhuǎn)換是高頻需求 —— 無論 ...
2025-09-18MySQL 大表拆分與關(guān)聯(lián)查詢效率:打破 “拆分必慢” 的認(rèn)知誤區(qū) 在 MySQL 數(shù)據(jù)庫管理中,“大表” 始終是性能優(yōu)化繞不開的話題。 ...
2025-09-18CDA 數(shù)據(jù)分析師:表結(jié)構(gòu)數(shù)據(jù) “獲取 - 加工 - 使用” 全流程的賦能者 表結(jié)構(gòu)數(shù)據(jù)(如數(shù)據(jù)庫表、Excel 表、CSV 文件)是企業(yè)數(shù)字 ...
2025-09-18DSGE 模型中的 Et:理性預(yù)期算子的內(nèi)涵、作用與應(yīng)用解析 動態(tài)隨機一般均衡(Dynamic Stochastic General Equilibrium, DSGE)模 ...
2025-09-17Python 提取 TIF 中地名的完整指南 一、先明確:TIF 中的地名有哪兩種存在形式? 在開始提取前,需先判斷 TIF 文件的類型 —— ...
2025-09-17CDA 數(shù)據(jù)分析師:解鎖表結(jié)構(gòu)數(shù)據(jù)特征價值的專業(yè)核心 表結(jié)構(gòu)數(shù)據(jù)(以 “行 - 列” 規(guī)范存儲的結(jié)構(gòu)化數(shù)據(jù),如數(shù)據(jù)庫表、Excel 表、 ...
2025-09-17Excel 導(dǎo)入數(shù)據(jù)含缺失值?詳解 dropna 函數(shù)的功能與實戰(zhàn)應(yīng)用 在用 Python(如 pandas 庫)處理 Excel 數(shù)據(jù)時,“缺失值” 是高頻 ...
2025-09-16深入解析卡方檢驗與 t 檢驗:差異、適用場景與實踐應(yīng)用 在數(shù)據(jù)分析與統(tǒng)計學(xué)領(lǐng)域,假設(shè)檢驗是驗證研究假設(shè)、判斷數(shù)據(jù)差異是否 “ ...
2025-09-16CDA 數(shù)據(jù)分析師:掌控表格結(jié)構(gòu)數(shù)據(jù)全功能周期的專業(yè)操盤手 表格結(jié)構(gòu)數(shù)據(jù)(以 “行 - 列” 存儲的結(jié)構(gòu)化數(shù)據(jù),如 Excel 表、數(shù)據(jù) ...
2025-09-16MySQL 執(zhí)行計劃中 rows 數(shù)量的準(zhǔn)確性解析:原理、影響因素與優(yōu)化 在 MySQL SQL 調(diào)優(yōu)中,EXPLAIN執(zhí)行計劃是核心工具,而其中的row ...
2025-09-15解析 Python 中 Response 對象的 text 與 content:區(qū)別、場景與實踐指南 在 Python 進(jìn)行 HTTP 網(wǎng)絡(luò)請求開發(fā)時(如使用requests ...
2025-09-15CDA 數(shù)據(jù)分析師:激活表格結(jié)構(gòu)數(shù)據(jù)價值的核心操盤手 表格結(jié)構(gòu)數(shù)據(jù)(如 Excel 表格、數(shù)據(jù)庫表)是企業(yè)最基礎(chǔ)、最核心的數(shù)據(jù)形態(tài) ...
2025-09-15Python HTTP 請求工具對比:urllib.request 與 requests 的核心差異與選擇指南 在 Python 處理 HTTP 請求(如接口調(diào)用、數(shù)據(jù)爬取 ...
2025-09-12解決 pd.read_csv 讀取長浮點數(shù)據(jù)的科學(xué)計數(shù)法問題 為幫助 Python 數(shù)據(jù)從業(yè)者解決pd.read_csv讀取長浮點數(shù)據(jù)時的科學(xué)計數(shù)法問題 ...
2025-09-12CDA 數(shù)據(jù)分析師:業(yè)務(wù)數(shù)據(jù)分析步驟的落地者與價值優(yōu)化者 業(yè)務(wù)數(shù)據(jù)分析是企業(yè)解決日常運營問題、提升執(zhí)行效率的核心手段,其價值 ...
2025-09-12用 SQL 驗證業(yè)務(wù)邏輯:從規(guī)則拆解到數(shù)據(jù)把關(guān)的實戰(zhàn)指南 在業(yè)務(wù)系統(tǒng)落地過程中,“業(yè)務(wù)邏輯” 是連接 “需求設(shè)計” 與 “用戶體驗 ...
2025-09-11塔吉特百貨孕婦營銷案例:數(shù)據(jù)驅(qū)動下的精準(zhǔn)零售革命與啟示 在零售行業(yè) “流量紅利見頂” 的當(dāng)下,精準(zhǔn)營銷成為企業(yè)突圍的核心方 ...
2025-09-11CDA 數(shù)據(jù)分析師與戰(zhàn)略 / 業(yè)務(wù)數(shù)據(jù)分析:概念辨析與協(xié)同價值 在數(shù)據(jù)驅(qū)動決策的體系中,“戰(zhàn)略數(shù)據(jù)分析”“業(yè)務(wù)數(shù)據(jù)分析” 是企業(yè) ...
2025-09-11Excel 數(shù)據(jù)聚類分析:從操作實踐到業(yè)務(wù)價值挖掘 在數(shù)據(jù)分析場景中,聚類分析作為 “無監(jiān)督分組” 的核心工具,能從雜亂數(shù)據(jù)中挖 ...
2025-09-10統(tǒng)計模型的核心目的:從數(shù)據(jù)解讀到?jīng)Q策支撐的價值導(dǎo)向 統(tǒng)計模型作為數(shù)據(jù)分析的核心工具,并非簡單的 “公式堆砌”,而是圍繞特定 ...
2025-09-10