ARTICLE · 1081405
别再手动填 Excel 了!用 Python 自动填充模板,1 分钟搞定 100 份
工资条、合同、报表、通知书……只要模板固定,Python 就能帮你批量生成。
今天分享一个非常实用的办公自动化技巧:用 Python 自动填充 Excel 模板,批量生成文件。
如果你经常遇到这些场景:
每月给 100 个员工发工资条,一个个复制粘贴;
给客户批量生成合同,只改姓名、金额、日期;
给每个班级生成成绩单,模板一样,数据不同;
手动改完还要另存为,文件名还不能错。
那这篇文章,建议你收藏。
一、整体思路
其实就三步:
准备一个 Excel 模板:固定不变的内容写好,变化的地方用占位符,比如
{{姓名}}、{{月份}}。准备一个数据源 Excel:第一行是字段名,下面每行是一条数据。
用 Python 读取数据,替换占位符,批量保存。
我们需要的库只有一个:openpyxl。
安装命令:
pip install openpyxl二、准备模板和数据
1. 模板文件:template.xlsx
比如工资条模板,内容如下:
| 单元格 | 内容 |
|---|---|
| B2 | 工资条 |
| B3 | 姓名:{{姓名}} |
| D3 | 月份:{{月份}} |
| B4 | 部门:{{部门}} |
| B6 | 基本工资:{{基本工资}} |
| D6 | 奖金:{{奖金}} |
| F6 | 合计:=C6+E6 |
其中 {{姓名}}、{{月份}} 这些就是占位符。
2. 数据源:data.xlsx
第一行是字段名,必须和占位符里的名字一致:
| 姓名 | 部门 | 月份 | 基本工资 | 奖金 |
|---|---|---|---|---|
| 张三 | 技术部 | 2025-06 | 8000 | 2000 |
| 李四 | 市场部 | 2025-06 | 7000 | 1500 |
| 王五 | 财务部 | 2025-06 | 7500 | 1800 |
三、完整 Python 代码
新建一个 auto_fill.py,复制下面代码:
from pathlib import Pathimport openpyxlTEMPLATE = Path("template.xlsx") # 模板文件DATA_FILE = Path("data.xlsx") # 数据源OUTPUT_DIR = Path("output") # 输出文件夹def replace_in_sheet(ws, data: dict):"""遍历工作表,替换所有 {{字段名}} 占位符"""for row in ws.iter_rows():for cell in row:if not isinstance(cell.value, str):continue# 情况1:单元格内容就是一个占位符,直接赋值,保留数字/日期类型if (cell.value.startswith("{{")and cell.value.endswith("}}")and cell.value.count("{{") == 1):key = cell.value[2:-2].strip()if key in data:cell.value = data[key]continue# 情况2:占位符混在文本里,做字符串替换new_value = cell.valuefor key, value in data.items():placeholder = "{{" + key + "}}"if placeholder in new_value:new_value = new_value.replace(placeholder, str(value))cell.value = new_valuedef read_data():"""读取数据源,返回字典列表"""wb = openpyxl.load_workbook(DATA_FILE, data_only=True)ws = wb.activerows = list(ws.iter_rows(values_only=True))if not rows:return []headers = rows[0]data_list = []for row in rows[1:]:if all(v is None for v in row):continuedata_list.append(dict(zip(headers, row)))return data_listdef safe_filename(name: str) -> str:"""去掉文件名中的非法字符"""for ch in ['\\', '/', ':', '*', '?', '"', '<', '>', '|']:name = name.replace(ch, "-")return name.strip()def main():OUTPUT_DIR.mkdir(exist_ok=True)data_list = read_data()for i, data in enumerate(data_list, start=1):wb = openpyxl.load_workbook(TEMPLATE)# 如果模板有多个工作表,全部替换for ws in wb.worksheets:replace_in_sheet(ws, data)# 生成文件名,例如:张三_2025-06.xlsxname = str(data.get("姓名", f"第{i}份"))month = str(data.get("月份", ""))filename = safe_filename(f"{name}_{month}.xlsx")wb.save(OUTPUT_DIR / filename)print(f"已生成:{filename}")if __name__ == "__main__":main()
python auto_fill.pyoutput 文件夹里就会自动生成:张三_2025-06.xlsx李四_2025-06.xlsx王五_2025-06.xlsx
每个文件都保留了你模板里的格式、公式、颜色、边框。
四、几个关键点
1. 占位符命名要统一
模板里写 {{姓名}},数据源表头也必须是 姓名。
建议不要带空格,比如 {{ 姓名 }} 容易匹配失败。
2. 数字类型会保留
代码里做了一个判断:
如果单元格内容只有一个占位符,比如 {{基本工资}},就直接把 Python 里的数字赋进去,不会变成文本。
如果占位符混在文本里,比如 姓名:{{姓名}},那结果就是字符串,这是正常的。
3. 公式不会被 openpyxl 计算
模板里的公式,比如 =C6+E6,openpyxl 保存后公式还在,但不会自动算出结果。
用 Excel 打开文件时,它会自动计算。
如果你希望生成后立即有值,可以用 xlwings 调用 Excel 计算。
4. 复杂模板建议用 xlwings
openpyxl 适合大多数普通表格,但它对图片、图表、宏、透视表的支持有限。
如果你的模板里有:
公司 Logo 图片
图表
宏
复杂条件格式
建议用 xlwings:
import xlwings as xwapp = xw.App(visible=False, add_book=False)wb = app.books.open("template.xlsx")sht = wb.sheets["工资条"]sht.range("B3").value = "张三"sht.range("D3").value = "2025-06"wb.save("output/张三.xlsx")wb.close()app.quit()
xlwings 会真正调用 Excel,所以格式、图片、公式都能保留,但电脑上必须安装 Excel。
五、还能怎么升级?
学会这个脚本后,你可以继续扩展:
用
schedule每天定时生成日报;用
PyQt做一个简单界面,让同事自己点按钮;用
PyInstaller打包成.exe,发给不会 Python 的同事;把数据源换成数据库,每天自动拉取;
生成 PDF:用
xlwings打开后另存为 PDF。
六、总结
核心就一句话:
模板里放占位符,数据源里放数据,Python 负责批量替换和保存。
以前手动改 100 份需要一上午,现在代码跑一遍,几十秒搞定,还不容易出错。