怎么用Python实现Excel自动化办公?实战案例教程
用Python实现Excel自动化,核心并不是“用代码重新做一遍Excel”,而是把那些需要重复打开文件、复制数据、填写公式、汇总结果和设置格式的操作交给程序。对于普通的 .xlsx 文件,可以使用 openpyxl 直接读取和修改工作簿;遇到数据量较大的清洗、筛选和统计任务,再配合 pandas 会更方便。
下面不只演示几个零散函数,而是从一个实际办公场景出发:读取销售明细表,自动计算销售额、汇总各部门数据、生成新的统计工作表并设置基础格式。掌握这个流程之后,日报、月报、库存表、财务汇总表等任务都可以采用类似的方法处理。
一、先弄清楚Python自动化Excel的处理流程
假设每天都会收到一份名为 sales.xlsx 的销售明细,其中包含日期、部门、商品、单价和数量。人工处理时,通常要增加销售额列,再按照部门汇总,最后整理成一份适合查看的报表。
Python可以把整个过程固定下来:
这里有一个很重要的思路:尽量让原始数据保持规则,例如第一行固定是字段名称,每一行表示一条记录,不要大量使用合并单元格。数据结构越稳定,自动化程序越容易长期复用。
二、准备Python环境和Excel示例文件
下面主要使用 openpyxl。它适合直接读取、创建和修改 .xlsx 工作簿,而且可以控制单元格内容、公式、颜色、字体、边框、列宽等。
在终端、PowerShell或命令提示符中安装:
python -m pip install openpyxl
如果后面还需要进行更复杂的数据筛选和统计,可以一起安装 pandas:
python -m pip install pandas openpyxl
本例假设当前目录有一个 sales.xlsx,其中工作表名称为“销售明细”,数据结构如下:
| 日期 | 部门 | 商品 | 单价 | 数量 |
|---|---|---|---|---|
| 2026-09-01 | 华东 | 产品A | 120 | 5 |
| 2026-09-01 | 华南 | 产品B | 80 | 12 |
| 2026-09-02 | 华东 | 产品C | 150 | 3 |
程序文件可以命名为 excel_report.py,目录结构保持简单:
excel_demo/
├── sales.xlsx
└── excel_report.py
openpyxl.py 或 pandas.py,否则导入对应库时可能发生名称冲突。
三、第一步:用Python读取Excel工作簿
先完成最基础的工作:打开文件、选择工作表,并确认程序确实读取到了数据。
from openpyxl import load_workbook
file_path = "sales.xlsx"
wb = load_workbook(file_path)
ws = wb["销售明细"]
print("工作表:", ws.title)
print("数据行数:", ws.max_row)
print("数据列数:", ws.max_column)
for row in ws.iter_rows(min_row=2, values_only=True):
print(row)
load_workbook() 会加载现有工作簿,wb["销售明细"] 用于选择指定工作表。由于第一行是表头,所以遍历数据时从 min_row=2 开始。
按照前面的示例文件,可能看到类似结果:
工作表: 销售明细
数据行数: 4
数据列数: 5
(datetime.datetime(2026, 9, 1, 0, 0), '华东', '产品A', 120, 5)
(datetime.datetime(2026, 9, 1, 0, 0), '华南', '产品B', 80, 12)
(datetime.datetime(2026, 9, 2, 0, 0), '华东', '产品C', 150, 3)
Excel中的日期可能会被读取成Python日期或日期时间对象,这是正常现象。后续如果只是把它继续保存到Excel,一般不需要手工转成字符串。
四、第二步:自动计算每条记录的销售额
现在给原表增加一列“销售额”。销售额的计算规则很直接:
销售额 = 单价 × 数量
按照当前表格结构,D列是单价,E列是数量,因此可以把结果写入F列。
from openpyxl import load_workbook
file_path = "sales.xlsx"
wb = load_workbook(file_path)
ws = wb["销售明细"]
ws["F1"] = "销售额"
for row in range(2, ws.max_row + 1):
price = ws.cell(row=row, column=4).value
quantity = ws.cell(row=row, column=5).value
if price is None or quantity is None:
amount = 0
else:
amount = price * quantity
ws.cell(row=row, column=6, value=amount)
wb.save("sales_processed.xlsx")
执行完成后,原始的 sales.xlsx 不会被覆盖,而是生成新的 sales_processed.xlsx。这种做法比较适合办公自动化,因为程序出现逻辑错误时仍然保留原始文件。
按照示例数据,新增列应该得到:
| 商品 | 单价 | 数量 | 销售额 |
|---|---|---|---|
| 产品A | 120 | 5 | 600 |
| 产品B | 80 | 12 | 960 |
| 产品C | 150 | 3 | 450 |
五、第三步:自动按部门汇总销售数据
只增加销售额还不够,办公报表更常见的要求是“按部门汇总”。可以使用一个字典保存每个部门累计的销售额。
summary = {}
for row in range(2, ws.max_row + 1):
department = ws.cell(row=row, column=2).value
amount = ws.cell(row=row, column=6).value
if not department:
continue
if amount is None:
amount = 0
summary[department] = summary.get(department, 0) + amount
print(summary)
使用前面的三条示例数据,结果为:
{'华东': 1050, '华南': 960}
summary.get(department, 0) 的意思是:如果部门已经出现过,就取出原来的累计金额;如果第一次出现,则从0开始。这样无论有几十条还是几万条记录,都可以采用同样的逻辑累加。
六、第四步:创建“部门汇总”工作表
接下来把统计结果写回Excel,而不是只打印在终端中。
if "部门汇总" in wb.sheetnames:
del wb["部门汇总"]
summary_ws = wb.create_sheet("部门汇总")
summary_ws.append(["部门", "销售总额"])
for department, total in summary.items():
summary_ws.append([department, total])
这里先检查工作簿中是否已经存在“部门汇总”。如果脚本重复运行,而旧工作表仍然存在,直接再次创建同名工作表会带来不必要的问题,所以先删除旧表再重新生成。
七、第五步:自动设置Excel报表格式
程序生成的Excel如果只是写入数据,通常还不够方便阅读。可以继续设置表头、数字格式、列宽和冻结窗格。
先引入需要的样式:
from openpyxl.styles import Font, PatternFill, Alignment, Border, Side
然后设置原始明细表:
header_fill = PatternFill("solid", fgColor="52677D")
header_font = Font(color="FFFFFF", bold=True)
thin_border = Border(
bottom=Side(style="thin", color="D9E0E6")
)
for cell in ws[1]:
cell.fill = header_fill
cell.font = header_font
cell.alignment = Alignment(horizontal="center", vertical="center")
for row in ws.iter_rows(min_row=2, max_row=ws.max_row):
for cell in row:
cell.border = thin_border
for row in range(2, ws.max_row + 1):
ws.cell(row=row, column=4).number_format = '#,##0.00'
ws.cell(row=row, column=6).number_format = '#,##0.00'
ws.column_dimensions["A"].width = 14
ws.column_dimensions["B"].width = 12
ws.column_dimensions["C"].width = 18
ws.column_dimensions["D"].width = 12
ws.column_dimensions["E"].width = 10
ws.column_dimensions["F"].width = 15
ws.freeze_panes = "A2"
freeze_panes = "A2" 表示冻结第一行。数据比较多时向下滚动,字段名称仍然会保留在顶部,这比仅调整颜色更有实际使用价值。
汇总表也可以使用相同的表头样式:
for cell in summary_ws[1]:
cell.fill = header_fill
cell.font = header_font
cell.alignment = Alignment(horizontal="center")
for row in range(2, summary_ws.max_row + 1):
summary_ws.cell(row=row, column=2).number_format = '#,##0.00'
summary_ws.column_dimensions["A"].width = 18
summary_ws.column_dimensions["B"].width = 18
八、把前面的步骤合成一个完整脚本
实际办公时不会分别运行几段代码,通常会把读取、计算、汇总、格式设置和保存组合成一个脚本。下面给出可以直接对应本案例的完整版本。
from openpyxl import load_workbook
from openpyxl.styles import Font, PatternFill, Alignment, Border, Side
INPUT_FILE = "sales.xlsx"
OUTPUT_FILE = "sales_processed.xlsx"
DETAIL_SHEET = "销售明细"
SUMMARY_SHEET = "部门汇总"
# 1. 打开Excel
wb = load_workbook(INPUT_FILE)
if DETAIL_SHEET not in wb.sheetnames:
raise ValueError(f"找不到工作表:{DETAIL_SHEET}")
ws = wb[DETAIL_SHEET]
# 2. 添加销售额字段
ws["F1"] = "销售额"
summary = {}
for row in range(2, ws.max_row + 1):
department = ws.cell(row=row, column=2).value
price = ws.cell(row=row, column=4).value
quantity = ws.cell(row=row, column=5).value
if price is None or quantity is None:
amount = 0
else:
amount = price * quantity
ws.cell(row=row, column=6, value=amount)
if department:
summary[department] = summary.get(department, 0) + amount
# 3. 删除旧汇总表并重新创建
if SUMMARY_SHEET in wb.sheetnames:
del wb[SUMMARY_SHEET]
summary_ws = wb.create_sheet(SUMMARY_SHEET)
summary_ws.append(["部门", "销售总额"])
for department, total in summary.items():
summary_ws.append([department, total])
# 4. 定义基础样式
header_fill = PatternFill("solid", fgColor="52677D")
header_font = Font(color="FFFFFF", bold=True)
thin_border = Border(
bottom=Side(style="thin", color="D9E0E6")
)
# 5. 明细表格式
for cell in ws[1]:
cell.fill = header_fill
cell.font = header_font
cell.alignment = Alignment(
horizontal="center",
vertical="center"
)
for row_cells in ws.iter_rows(
min_row=2,
max_row=ws.max_row,
min_col=1,
max_col=6
):
for cell in row_cells:
cell.border = thin_border
for row in range(2, ws.max_row + 1):
ws.cell(row=row, column=4).number_format = '#,##0.00'
ws.cell(row=row, column=6).number_format = '#,##0.00'
ws.column_dimensions["A"].width = 14
ws.column_dimensions["B"].width = 12
ws.column_dimensions["C"].width = 18
ws.column_dimensions["D"].width = 12
ws.column_dimensions["E"].width = 10
ws.column_dimensions["F"].width = 15
ws.freeze_panes = "A2"
# 6. 汇总表格式
for cell in summary_ws[1]:
cell.fill = header_fill
cell.font = header_font
cell.alignment = Alignment(horizontal="center")
for row in range(2, summary_ws.max_row + 1):
summary_ws.cell(row=row, column=2).number_format = '#,##0.00'
summary_ws.column_dimensions["A"].width = 18
summary_ws.column_dimensions["B"].width = 18
# 7. 保存为新文件
wb.save(OUTPUT_FILE)
print(f"处理完成:{OUTPUT_FILE}")
在脚本所在目录执行:
python excel_report.py
正常完成后,会生成:
sales_processed.xlsx
打开该文件,应当能确认三件事:销售明细中出现了“销售额”列;工作簿增加了“部门汇总”工作表;表头、数字格式、列宽和冻结首行已经应用。
九、数据量较大时,可以用pandas处理再写回Excel
openpyxl 的优势是能够直接控制工作簿和单元格,但如果任务主要是筛选、分组、合并、统计数据,pandas 的写法通常更简洁。
例如同样的部门销售汇总,可以这样处理:
import pandas as pd
df = pd.read_excel(
"sales.xlsx",
sheet_name="销售明细"
)
df["销售额"] = df["单价"].fillna(0) * df["数量"].fillna(0)
summary = (
df.groupby("部门", as_index=False)["销售额"]
.sum()
.rename(columns={"销售额": "销售总额"})
)
with pd.ExcelWriter(
"sales_pandas.xlsx",
engine="openpyxl"
) as writer:
df.to_excel(
writer,
sheet_name="销售明细",
index=False
)
summary.to_excel(
writer,
sheet_name="部门汇总",
index=False
)
这里的 groupby("部门") 就完成了按部门分组,随后对“销售额”求和。对于需要按地区、员工、产品、日期等多个条件统计的表格,这种方式会比手工遍历单元格更容易维护。
可以简单理解:
| 需求 | 更合适的工具 |
|---|---|
| 修改指定单元格、字体、颜色、边框、公式 | openpyxl |
| 筛选、分组、排序、统计大量表格数据 | pandas |
| 既要统计数据,又要精细调整最终Excel格式 | pandas + openpyxl |
十、进一步实现批量处理多个Excel文件
真正能明显减少重复劳动的场景,往往不是处理一个文件,而是一个文件夹里每天、每周或者每个部门各有一份Excel。
例如目录中存在:
reports/
├── 华东销售.xlsx
├── 华南销售.xlsx
├── 华北销售.xlsx
└── 西南销售.xlsx
可以利用Python的 pathlib 扫描目录:
from pathlib import Path
from openpyxl import load_workbook
folder = Path("reports")
for file_path in folder.glob("*.xlsx"):
print("正在处理:", file_path.name)
wb = load_workbook(file_path)
ws = wb["销售明细"]
ws["F1"] = "销售额"
for row in range(2, ws.max_row + 1):
price = ws.cell(row=row, column=4).value or 0
quantity = ws.cell(row=row, column=5).value or 0
ws.cell(
row=row,
column=6,
value=price * quantity
)
output_path = file_path.with_name(
file_path.stem + "_处理后.xlsx"
)
wb.save(output_path)
这样脚本会查找 reports 目录中的所有 .xlsx 文件,并分别生成带“_处理后”后缀的新文件。
~$ 开头的临时文件。批量脚本可以增加判断,跳过这类文件:
if file_path.name.startswith("~$"):
continue
十一、实际办公自动化中最容易出错的地方
1. Excel列位置发生变化
前面的程序假设“部门”固定在B列、“单价”固定在D列。如果有人把“单价”移动到E列,程序仍然读取D列,就会产生错误结果。
更稳妥的方式是根据表头寻找列,而不是把列号完全写死。例如:
headers = {}
for cell in ws[1]:
headers[cell.value] = cell.column
price_col = headers["单价"]
quantity_col = headers["数量"]
department_col = headers["部门"]
后面的代码再使用 price_col、quantity_col 和 department_col。这样即使列顺序变化,只要表头名称没有变,程序仍然能够找到正确字段。
2. 单元格中存在空值或文本
实际表格不一定像示例这么整齐。某一行的单价可能为空,也可能误填成“待确认”。如果直接执行乘法,会出现异常。
需要先验证数据类型:
if isinstance(price, (int, float)) and isinstance(quantity, (int, float)):
amount = price * quantity
else:
amount = 0
正式业务中是否应该把异常值当作0,要根据实际规则决定。很多情况下,更合适的做法不是默默改成0,而是把异常行记录下来,等待人工确认。
3. 不要一开始就覆盖原始文件
如果直接:
wb.save("sales.xlsx")
原始文件会被新结果替换。程序逻辑尚未经过验证时,更建议输出到新文件,例如:
wb.save("sales_processed.xlsx")
等脚本稳定以后,再根据业务需要决定是否覆盖原文件。
4. 公式和公式结果不是一回事
Excel中可以存在公式,例如:
=D2*E2
openpyxl 可以读取和写入公式,但它本身不是Excel的完整公式计算引擎。也就是说,把公式写入工作簿并不等于Python已经重新计算出了所有Excel公式结果。
如果自动化任务需要立即得到计算结果,最可靠的方式之一是直接在Python中完成相应计算,然后把数值写入单元格。
5. 合并单元格适合展示,不适合原始数据
如果一张表大量使用合并单元格来表示部门、地区或分类,从人的视觉角度看可能比较整齐,但对程序来说会增加读取难度。
用于自动处理的原始表最好保持“一行一条记录、每列一个字段”。最终生成给人阅读的报表时,再根据需要增加展示格式。
十二、什么时候适合用Python做Excel自动化
并不是所有Excel操作都值得写程序。只有偶尔修改三五个单元格,直接使用Excel通常更快。Python更适合具有明显重复性的任务,例如:
- 每天都要把相同格式的数据整理成日报;
- 几十个Excel文件需要执行相同的计算或格式调整;
- 需要按照部门、地区、产品等字段自动统计;
- 需要把多个表格合并成一份总表;
- 需要批量检查空值、重复数据或异常数据;
- 需要定期生成结构固定的Excel报表。
判断是否值得自动化,可以看一个很简单的条件:操作规则是否明确并且会重复出现。规则越固定、重复次数越多,Python脚本的价值越明显。
十三、完整思路总结
用Python实现Excel自动化办公,可以先从一个非常具体的重复任务开始,而不是一开始就尝试建立复杂的办公系统。本例的过程就是一个可以复用的基本模板:读取 sales.xlsx,逐行计算销售额,按照部门汇总数据,创建新的汇总工作表,再设置必要的Excel格式并输出新文件。
如果任务重点是修改工作簿结构、单元格和格式,使用 openpyxl 比较直接;如果重点是大量数据的筛选、分组和统计,可以先用 pandas 处理,再根据需要使用 openpyxl 调整最终报表。
真正开始用于日常工作后,还应逐步处理三个问题:不要过度依赖固定列号,要检查空值和异常数据,并且在脚本经过验证之前保留原始文件。做到这些之后,原本每天都需要手工重复的Excel整理流程,就可以变成“放入新数据、运行脚本、检查结果”这样相对稳定的自动化过程。
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













