使用Python?openpyxl批量處理Excel的操作指南
前言:我們?yōu)楹我c重復(fù)勞動說再見?
想象一下這些場景:
- 每月底:你需要從20個部門的Excel報(bào)表中,手動匯總銷售數(shù)據(jù)到一個總表,并計(jì)算環(huán)比、同比。
- 每周一:你要將系統(tǒng)導(dǎo)出的原始數(shù)據(jù),進(jìn)行格式清洗、空值填充、錯誤修正,生成給領(lǐng)導(dǎo)看的周報(bào)。
- 每天下班前:你要將幾十個同事提交的進(jìn)度表合并,并高亮顯示延遲的任務(wù)。
這些工作技術(shù)含量不高,但極其耗時、枯燥且容易出錯。一旦某個步驟出錯,可能需要從頭再來。更令人沮喪的是,這類“表哥表姐”的工作占據(jù)了大量本該用于思考和創(chuàng)造的時間。
Python 的 openpyxl 庫正是為此而生。它允許我們以編程方式操作 .xlsx 格式的 Excel 文件,實(shí)現(xiàn)讀取、寫入、修改、格式化和圖表生成等幾乎所有手動操作。學(xué)習(xí)它,不是要成為Excel專家,而是要成為自動化流程的設(shè)計(jì)師,將規(guī)則固定成代碼,一勞永逸。本文將帶你從零開始,深入原理,掌握用代碼駕馭Excel的完整能力。
第一章:環(huán)境搭建與核心概念初探
在開始編寫自動化腳本之前,我們需要確保環(huán)境正確。本文所有代碼基于 Python 3.10+ 和 openpyxl 3.1+。
安裝 openpyxl: 打開你的終端或命令提示符,執(zhí)行以下命令:
pip install openpyxl
理解 openpyxl 的核心對象模型: openpyxl 將 Excel 文件抽象為三個核心層級,理解它們對后續(xù)編程至關(guān)重要:
- Workbook(工作簿):對應(yīng)一個
.xlsx文件。 - Worksheet(工作表):對應(yīng)工作簿里的一個
Sheet(如Sheet1)。 - Cell(單元格):工作表中最基本的單元,通過列字母和行號定位(如
A1)。
當(dāng)我們用 openpyxl 加載一個 Excel 文件時,內(nèi)存中就會建立起這樣一個對象樹,我們的所有操作都是對這些對象的屬性進(jìn)行修改,最后再保存到磁盤。
第一個“Hello World”程序: 讓我們創(chuàng)建一個新的Excel文件并寫入內(nèi)容。
from openpyxl import Workbook
# 1. 創(chuàng)建一個新的工作簿(Workbook)對象
wb = Workbook()
# 默認(rèn)會創(chuàng)建一個名為‘Sheet'的工作表,我們通過 active 屬性獲取它
ws = wb.active
ws.title = "我的第一個Sheet" # 給工作表重命名
# 2. 操作單元格(Cell)
# 方法一:通過類似字典的鍵(單元格坐標(biāo))來訪問
ws['A1'] = "你好,Excel!"
# 方法二:使用 .cell(row, column, value) 方法,更便于循環(huán)
ws.cell(row=2, column=1, value="這是第二行") # 相當(dāng)于 A2
# 3. 保存工作簿到文件
wb.save("hello_openpyxl.xlsx")
print("Excel文件已生成!")運(yùn)行這段代碼,你會在當(dāng)前目錄下看到 hello_openpyxl.xlsx,打開它,A1和A2單元格已成功寫入數(shù)據(jù)。
小結(jié):Workbook() 創(chuàng)建,ws['A1'] 或 ws.cell() 寫入,wb.save() 保存,這是最基礎(chǔ)的操作三部曲。
第二章:深入讀寫——駕馭數(shù)據(jù)的輸入與輸出
自動化處理的核心是數(shù)據(jù)。本章我們學(xué)習(xí)如何從現(xiàn)有文件讀取數(shù)據(jù),以及如何將處理好的數(shù)據(jù)寫入指定位置。
加載已有工作簿: 使用 load_workbook 函數(shù),注意 data_only 參數(shù):為 False(默認(rèn))時,讀取的是單元格的原始內(nèi)容(如公式=A1+B1);為 True 時,讀取的是單元格計(jì)算后的值(如 5)。
from openpyxl import load_workbook
# 加載一個已存在的Excel文件
wb = load_workbook(filename='example.xlsx') # 假設(shè)此文件存在
# 獲取所有工作表的名稱
sheet_names = wb.sheetnames
print(f"所有工作表:{sheet_names}")
# 通過名稱獲取特定工作表
ws = wb['Sheet1'] # 或 wb[sheet_names[0]]
# 讀取單元格內(nèi)容
cell_value = ws['B5'].value
print(f"B5單元格的值是:{cell_value}")
# 讀取一系列單元格:使用切片或iter_rows
for row in ws['A1':'C3']: # 讀取A1到C3這個矩形區(qū)域
for cell in row:
print(cell.coordinate, cell.value) # 打印坐標(biāo)和值
print("---行結(jié)束---")高效遍歷與寫入數(shù)據(jù): 對于大數(shù)據(jù)量,使用 iter_rows 或 iter_cols 方法進(jìn)行逐行/逐列遍歷,性能更好。
# 假設(shè)我們要處理一個員工信息表
data_to_write = [
['工號', '姓名', '部門', '薪資'],
['001', '張三', '技術(shù)部', 15000],
['002', '李四', '市場部', 12000],
['003', '王五', '技術(shù)部', 18000],
]
# 從第1行開始,寫入數(shù)據(jù)
start_row = 1
for i, row_data in enumerate(data_to_write, start=start_row):
for j, cell_value in enumerate(row_data, start=1): # 列從1開始
ws.cell(row=i, column=j, value=cell_value)
# 在末尾追加一行數(shù)據(jù)(獲取最大行號)
max_row = ws.max_row
ws.cell(row=max_row+1, column=1, value='004')
ws.cell(row=max_row+1, column=2, value='趙六')
# ... 可以繼續(xù)寫入其他列
wb.save('updated_example.xlsx')注意事項(xiàng):ws.max_row 和 ws.max_column 返回的是工作表中有數(shù)據(jù)的最大行和列,是動態(tài)獲取的,非常有用。
第三章:樣式與格式——讓報(bào)表“專業(yè)”起來
一份給領(lǐng)導(dǎo)看的報(bào)表,光有數(shù)據(jù)還不夠,還需要清晰的格式。openpyxl 的樣式功能非常強(qiáng)大。
核心樣式對象:
Font(字體):大小、顏色、加粗、斜體。PatternFill(填充):單元格背景色。Border(邊框):單元格的邊框線。Alignment(對齊):水平對齊、垂直對齊、自動換行。NamedStyle(命名樣式):可以復(fù)用的樣式集合。
給單元格“化妝”:
from openpyxl.styles import Font, PatternFill, Alignment, Border, Side
from openpyxl.styles import numbers
# 1. 設(shè)置字體和填充(表頭樣式)
header_font = Font(name='微軟雅黑', size=12, bold=True, color='FFFFFF') # 白色加粗
header_fill = PatternFill(fill_type='solid', fgColor='366092') # 深藍(lán)色填充
for cell in ws[1]: # 遍歷第一行的所有單元格
cell.font = header_font
cell.fill = header_fill
cell.alignment = Alignment(horizontal='center', vertical='center') # 居中
# 2. 設(shè)置數(shù)字格式(例如,將薪資列設(shè)置為千位分隔符和兩位小數(shù))
salary_column = 4 # 假設(shè)薪資在第4列
for row in ws.iter_rows(min_row=2, min_col=salary_column, max_col=salary_column):
for cell in row:
cell.number_format = numbers.FORMAT_NUMBER_COMMA_SEPARATED1 # '#,##0.00'
# 3. 設(shè)置邊框
thin_border = Border(
left=Side(style='thin'),
right=Side(style='thin'),
top=Side(style='thin'),
bottom=Side(style='thin')
)
# 為A1到D5區(qū)域設(shè)置邊框
for row in ws.iter_rows(min_row=1, max_row=5, min_col=1, max_col=4):
for cell in row:
cell.border = thin_border
# 4. 調(diào)整列寬和行高
ws.column_dimensions['B'].width = 15 # 設(shè)置B列寬
ws.row_dimensions[1].height = 25 # 設(shè)置第1行高小結(jié):樣式操作雖然代碼稍多,但邏輯清晰。通常我們會將常用的樣式(如表頭、高亮、警告)定義為函數(shù)或 NamedStyle,方便全局調(diào)用,保持報(bào)表風(fēng)格統(tǒng)一。
第四章:公式、圖表與高級操作
Excel的靈魂在于公式和圖表,openpyxl 同樣支持。
插入與計(jì)算公式: 只需像在Excel里一樣,將公式字符串賦值給單元格即可。注意,公式以等號 = 開頭。
# 在E2單元格插入求和公式,計(jì)算B2到D2的和
ws['E2'] = '=SUM(B2:D2)'
# 在F列計(jì)算薪資的稅率(假設(shè)稅率為10%)
for row in range(2, ws.max_row + 1):
salary_cell = ws.cell(row=row, column=4) # 薪資列
tax_cell = ws.cell(row=row, column=6) # 稅率結(jié)果列
tax_cell.value = f'={salary_cell.coordinate} * 0.1' # 如 =D2*0.1重要提示:openpyxl 只負(fù)責(zé)寫入公式字符串。當(dāng)你在Excel中打開文件時,Excel會計(jì)算公式結(jié)果。如果你需要在Python中獲取公式的計(jì)算結(jié)果,必須在Excel中計(jì)算并保存后,再用 load_workbook(filename, data_only=True) 加載,才能讀到值。
創(chuàng)建圖表: openpyxl 支持創(chuàng)建柱狀圖、折線圖、餅圖等多種圖表。
from openpyxl.chart import BarChart, Reference # 假設(shè)數(shù)據(jù)在A1到D4區(qū)域,A列為類別,B-D列為數(shù)據(jù)系列 data = Reference(ws, min_col=2, min_row=1, max_col=4, max_row=4) # B1:D4 categories = Reference(ws, min_col=1, min_row=2, max_row=4) # A2:A4 # 創(chuàng)建柱狀圖 chart = BarChart() chart.title = "部門業(yè)績對比" chart.x_axis.title = "部門" chart.y_axis.title = "業(yè)績" chart.add_data(data, titles_from_data=True) # 從數(shù)據(jù)第一行讀取系列標(biāo)題 chart.set_categories(categories) # 將圖表插入到工作表的 F1 單元格位置 ws.add_chart(chart, "F1")
第五章:批量處理的精髓——操作多個文件與工作表
真正的自動化是處理成百上千個文件。這需要結(jié)合Python的文件操作(os 或 pathlib 模塊)。
批量合并多個Excel文件: 假設(shè)有一個文件夾,里面是所有銷售員的每日業(yè)績表(格式相同),我們需要合并到一個總表。
import os
from openpyxl import load_workbook
source_folder = './daily_reports/'
output_file = './merged_report.xlsx'
# 創(chuàng)建一個新的工作簿用于存放合并結(jié)果
merged_wb = Workbook()
merged_ws = merged_wb.active
merged_ws.title = '合并數(shù)據(jù)'
header_written = False # 標(biāo)記表頭是否已寫入
# 遍歷文件夾下所有.xlsx文件
for filename in os.listdir(source_folder):
if filename.endswith('.xlsx'):
filepath = os.path.join(source_folder, filename)
print(f'正在處理:{filename}')
wb = load_workbook(filepath, data_only=True)
ws = wb.active
# 如果是第一個文件,寫入表頭
if not header_written:
for row in ws.iter_rows(min_row=1, max_row=1, values_only=True):
merged_ws.append(row) # append方法可以按行添加一個可迭代對象
header_written = True
# 從第二行開始,寫入數(shù)據(jù)
for row in ws.iter_rows(min_row=2, values_only=True):
merged_ws.append(row)
merged_wb.save(output_file)
print(f'所有文件合并完成,結(jié)果保存在:{output_file}')
操作工作簿內(nèi)的多個工作表:
# 1. 創(chuàng)建和刪除工作表
wb.create_sheet(title='月度匯總', index=0) # 在第一個位置創(chuàng)建
if '無用Sheet' in wb.sheetnames:
useless_sheet = wb['無用Sheet']
wb.remove(useless_sheet) # 刪除工作表
# 2. 復(fù)制工作表內(nèi)容
source = wb['原始數(shù)據(jù)']
target = wb.create_sheet('備份數(shù)據(jù)')
for row in source.iter_rows(values_only=True):
target.append(row)
完整實(shí)戰(zhàn)案例:自動生成月度部門薪資報(bào)告
場景:你作為HR,每月需要從財(cái)務(wù)系統(tǒng)導(dǎo)出原始薪資數(shù)據(jù)(raw_salary.xlsx),然后進(jìn)行以下操作:
- 清洗數(shù)據(jù)(刪除測試部門、填充空值)。
- 按部門分類匯總,計(jì)算各部門平均薪資、最高薪資。
- 生成一個格式美觀的匯總報(bào)告,并高亮顯示平均薪資高于公司平均的部門。
- 將每個部門的數(shù)據(jù)單獨(dú)保存到一個新的工作表。
代碼實(shí)現(xiàn):
import os
from openpyxl import load_workbook, Workbook
from openpyxl.styles import Font, PatternFill, Alignment, numbers
from openpyxl.chart import BarChart, Reference
def generate_monthly_salary_report():
"""生成月度薪資報(bào)告主函數(shù)"""
# 1. 加載原始數(shù)據(jù)
raw_wb = load_workbook('raw_salary.xlsx', data_only=True)
raw_ws = raw_wb.active
# 數(shù)據(jù)結(jié)構(gòu):按部門分組,存儲員工薪資列表
dept_salary_dict = {}
company_total = 0
employee_count = 0
# 2. 數(shù)據(jù)清洗與分組 (假設(shè)數(shù)據(jù)從第2行開始,A:姓名 B:部門 C:薪資)
for row in raw_ws.iter_rows(min_row=2, values_only=True):
name, dept, salary = row
# 清洗:跳過測試部門和薪資為空的數(shù)據(jù)
if dept == '測試部' or salary is None:
continue
# 分組
if dept not in dept_salary_dict:
dept_salary_dict[dept] = []
dept_salary_dict[dept].append(salary)
# 計(jì)算公司總和,用于后續(xù)求平均
company_total += salary
employee_count += 1
if employee_count == 0:
print("沒有有效數(shù)據(jù)!")
return
company_avg = company_total / employee_count
# 3. 創(chuàng)建報(bào)告工作簿
report_wb = Workbook()
# 移除默認(rèn)sheet,創(chuàng)建匯總sheet
default_sheet = report_wb.active
report_wb.remove(default_sheet)
summary_ws = report_wb.create_sheet('部門匯總')
# 4. 寫入?yún)R總表頭并設(shè)置樣式
headers = ['部門', '員工數(shù)', '總薪資', '平均薪資', '最高薪資', '超過公司平均']
for col_idx, header in enumerate(headers, start=1):
cell = summary_ws.cell(row=1, column=col_idx, value=header)
cell.font = Font(bold=True)
cell.fill = PatternFill(fill_type='solid', fgColor='DDDDDD')
cell.alignment = Alignment(horizontal='center')
# 5. 計(jì)算并寫入各部門數(shù)據(jù)
row_idx = 2
highlight_fill = PatternFill(fill_type='solid', fgColor='FFFF00') # 黃色高亮
for dept, salaries in dept_salary_dict.items():
emp_count = len(salaries)
dept_total = sum(salaries)
dept_avg = dept_total / emp_count
dept_max = max(salaries)
is_above_avg = dept_avg > company_avg
summary_ws.cell(row=row_idx, column=1, value=dept)
summary_ws.cell(row=row_idx, column=2, value=emp_count)
summary_ws.cell(row=row_idx, column=3, value=dept_total).number_format = numbers.FORMAT_NUMBER_COMMA_SEPARATED1
summary_ws.cell(row=row_idx, column=4, value=dept_avg).number_format = numbers.FORMAT_NUMBER_COMMA_SEPARATED1
summary_ws.cell(row=row_idx, column=5, value=dept_max).number_format = numbers.FORMAT_NUMBER_COMMA_SEPARATED1
summary_ws.cell(row=row_idx, column=6, value='是' if is_above_avg else '否')
# 如果超過公司平均,高亮該行平均薪資單元格
if is_above_avg:
summary_ws.cell(row=row_idx, column=4).fill = highlight_fill
# 6. 為每個部門創(chuàng)建詳細(xì)數(shù)據(jù)工作表
detail_ws = report_wb.create_sheet(title=dept[:31]) # 工作表名最多31字符
detail_ws.append(['姓名', '薪資'])
for salary in salaries:
# 在真實(shí)場景中,這里應(yīng)該對應(yīng)姓名,本例簡化處理
detail_ws.append([f'員工{row_idx}', salary])
row_idx += 1
# 7. 在匯總表末尾添加公司平均數(shù)據(jù)
footer_row = row_idx + 1
summary_ws.cell(row=footer_row, column=1, value='公司整體')
summary_ws.cell(row=footer_row, column=2, value=employee_count)
summary_ws.cell(row=footer_row, column=3, value=company_total).number_format = numbers.FORMAT_NUMBER_COMMA_SEPARATED1
summary_ws.cell(row=footer_row, column=4, value=company_avg).number_format = numbers.FORMAT_NUMBER_COMMA_SEPARATED1
summary_ws.cell(row=footer_row, column=4).font = Font(bold=True, color='FF0000')
# 8. 為匯總表創(chuàng)建圖表(各部門平均薪資對比)
chart = BarChart()
chart.title = "各部門平均薪資對比"
chart.x_axis.title = "部門"
chart.y_axis.title = "平均薪資"
# 數(shù)據(jù)范圍:A列部門名(從第2行到倒數(shù)第二行),D列平均薪資
data = Reference(summary_ws, min_col=4, min_row=2, max_row=row_idx-1)
categories = Reference(summary_ws, min_col=1, min_row=2, max_row=row_idx-1)
chart.add_data(data, titles_from_data=False)
chart.set_categories(categories)
summary_ws.add_chart(chart, f"H2")
# 9. 調(diào)整列寬
for column in summary_ws.columns:
max_length = 0
column_letter = column[0].column_letter
for cell in column:
try:
if len(str(cell.value)) > max_length:
max_length = len(str(cell.value))
except:
pass
adjusted_width = (max_length + 2)
summary_ws.column_dimensions[column_letter].width = adjusted_width
# 10. 保存報(bào)告
report_wb.save('月度薪資分析報(bào)告.xlsx')
print(f"報(bào)告生成成功!已處理 {len(dept_salary_dict)} 個部門的數(shù)據(jù)。")
if __name__ == '__main__':
generate_monthly_salary_report()
這個案例綜合運(yùn)用了數(shù)據(jù)讀取、清洗、分組計(jì)算、多工作表操作、樣式設(shè)置和圖表生成,是一個接近真實(shí)場景的自動化腳本。你可以根據(jù)實(shí)際數(shù)據(jù)格式調(diào)整列索引和清洗邏輯。
常見問題 & 踩坑記錄
- 文件被占用,無法保存:這是最常見的問題。確保你的Excel文件沒有被其他程序(如微軟Excel、WPS)打開。在代碼中,完成所有操作后,確保執(zhí)行了
wb.save('新文件名.xlsx'),Python會正確關(guān)閉文件句柄。 - 讀取公式得到的是公式本身,而不是計(jì)算結(jié)果:這是因?yàn)榧虞d工作簿時使用了默認(rèn)參數(shù)
data_only=False。如果需要讀取計(jì)算后的值,必須在Excel中計(jì)算并保存文件后,使用load_workbook(filename, data_only=True)來加載。openpyxl本身不計(jì)算Excel公式。 - 修改后保存,原文件格式丟失(如行高列寬):
openpyxl在保存時,會保留它能夠識別的所有屬性。但一些非常復(fù)雜或特定的格式(如某些條件格式、自定義視圖)可能會丟失。對于重要文件,建議先備份。 - 處理大量數(shù)據(jù)時內(nèi)存占用高或速度慢:
openpyxl默認(rèn)將整個工作簿加載到內(nèi)存。對于超大型文件(如幾十MB以上),可以考慮:- 使用
read_only=True模式只讀加載,僅用于讀取數(shù)據(jù)。 - 使用
write_only=True模式創(chuàng)建僅用于寫入的工作簿,適合生成大型報(bào)表。 - 對于純數(shù)據(jù)讀寫,
pandas庫的read_excel和to_excel函數(shù)性能可能更優(yōu),但會丟失格式。
- 使用
- 中文字體或編碼問題:在設(shè)置字體時,使用系統(tǒng)內(nèi)存在的字體名稱(如
Font(name='Microsoft YaHei'))。如果單元格顯示亂碼,檢查Python腳本文件的保存編碼是否為UTF-8。
總結(jié) & 延伸閱讀
通過本文,我們系統(tǒng)地掌握了使用 openpyxl 自動化處理Excel的核心技能:從基礎(chǔ)讀寫、樣式美化,到公式圖表、批量操作,最后完成了一個綜合實(shí)戰(zhàn)案例。自動化不是要替代Excel,而是將你從重復(fù)、機(jī)械的勞動中解放出來,讓你有更多時間專注于數(shù)據(jù)分析、邏輯判斷和決策本身。
進(jìn)階方向:
- 結(jié)合其他庫:將
openpyxl與pandas結(jié)合。用pandas做復(fù)雜的數(shù)據(jù)分析和轉(zhuǎn)換(如數(shù)據(jù)透 視表、分組聚合),再用openpyxl進(jìn)行精細(xì)的格式調(diào)整和輸出。 - 開發(fā)GUI工具:使用
PyQt、Tkinter或Streamlit為你的自動化腳本制作一個可視化界面,交給非技術(shù)同事使用。 - 定時任務(wù)與郵件發(fā)送:使用
schedule或操作系統(tǒng)的定時任務(wù)(如cron, Windows任務(wù)計(jì)劃程序),讓腳本定期自動運(yùn)行,并結(jié)合smtplib庫將生成的報(bào)告自動發(fā)送給相關(guān)人員。 - 處理更老格式:如果需要處理
.xls格式的文件,可以了解xlrd和xlwt庫。
記住,自動化的第一步,就是把今天手動做的事情,用代碼描述出來。從一個小任務(wù)開始,逐步構(gòu)建你的自動化工具箱吧!
以上就是使用Python openpyxl批量處理Excel的操作指南的詳細(xì)內(nèi)容,更多關(guān)于Python openpyxl批量處理Excel的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
詳解Python實(shí)現(xiàn)進(jìn)度條的4種方式
這篇文章主要介紹了Python實(shí)現(xiàn)進(jìn)度條的4種方式,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-01-01
Python實(shí)現(xiàn)Excel表格轉(zhuǎn)置與翻譯工具
本文主要介紹如何使用Python編寫一個GUI程序,能夠讀取Excel文件,將第一個列的數(shù)據(jù)轉(zhuǎn)置,并將英文內(nèi)容翻譯成中文,有需要的小伙伴可以參考一下2024-10-10
基于python的docx模塊處理word和WPS的docx格式文件方式
今天小編就為大家分享一篇基于python的docx模塊處理word和WPS的docx格式文件方式,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-02-02
淺談spring boot 集成 log4j 解決與logback沖突的問題
今天小編就為大家分享一篇淺談spring boot 集成 log4j 解決與logback沖突的問題,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-02-02
通過 Django Pagination 實(shí)現(xiàn)簡單分頁功能
這篇文章主要介紹了通過 Django Pagination 實(shí)現(xiàn)簡單分頁功能,非常不錯,具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-11-11
AUC計(jì)算方法與Python實(shí)現(xiàn)代碼
今天小編就為大家分享一篇AUC計(jì)算方法與Python實(shí)現(xiàn)代碼,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-02-02

