2026-10-05 · 本脚本已实跑验证(3行名单 → 3份文档,逐字复核通过)
人事、行政、班主任最常问的需求:"我有一份Excel名单,要给每个人生成一份Word通知,人名/部门/金额都不一样,难道要复制粘贴50遍吗?" 不用。这就是Word自带的"邮件合并"干的活,但很多人装了Word一辈子没用过那个按钮。这里给纯Python版,免装Word、可跑在服务器上。
名单.xlsx:
姓名 部门 工资 日期 张三 技术部 15000 2026年9月 李四 市场部 12000 2026年9月 王五 财务部 13500 2026年9月
模板.docx 里写占位符:【姓名】您好:您【部门】本月工资为【工资】元。
import openpyxl, os
from docx import Document
PLACEHOLDERS = ['【姓名】', '【部门】', '【工资】', '【日期】']
rows = list(openpyxl.load_workbook('名单.xlsx').active
.iter_rows(min_row=2, values_only=True))
os.makedirs('out', exist_ok=True)
for r in rows:
d = Document('模板.docx')
for p in d.paragraphs:
for run in p.runs:
for k, v in zip(PLACEHOLDERS, r):
run.text = run.text.replace(k, str(v))
d.save(f'out/{r[0]}.docx')
实跑输出:张三.docx / 李四.docx / 王五.docx,复核"张三.docx"正文为「张三您好:您技术部本月工资为15000元,发放日期2026年9月。」——三个占位符全部正确替换。
这是Word文档处理里最阴的坑。Word会在你打字时随手插入"运行片段(run)"——你在【部】和【门】中间点过一次鼠标,这两个字就分属两个run。逐run替换时每个run里都只占位符的一半,一个都匹配不上,什么也不报错,输出原样保留【部门】。实测:把"【部门】""【工资】"故意拆进3个run,逐run替换后输出仍是「您【部门】本月工资为【工资】元」。
正确做法:先拼接整段再替换,写回第一个run:
for p in d.paragraphs:
merged = ''.join(r.text for r in p.runs)
for k, v in pairs:
merged = merged.replace(k, v)
if p.runs:
p.runs[0].text = merged
for r in p.runs[1:]:
r.text = ''
(代价是丢失run中间的局部格式;模板里整段同格式时完全没问题。表格单元格要再遍历 table.rows → row.cells → cell.paragraphs。)
Excel里工资列存的是数字。哪怕显示成"15,000.00",openpyxl读出来是float 15000.0,str()之后通知单上就写着"工资为15000.0元"。实跑确认:单元格值 15000.00 → str 后是 15000.0。工资、编号这类列要么在Excel里设为文本格式,要么代码里做 v = int(v) if v == int(v) else v。
名单里两个"张伟",第二份会静默覆盖第一份——你少发一份通知,没人提醒你。out/{r[0]}.docx 前先检查重名(计数或加工号后缀),或直接用 out/01_张三.docx 带序号命名。
懒得装Python环境?喵窝提供表格/文档代做服务(¥19.9):把你的Excel和模板发给我们,交付现成的批量脚本+生成的成品文档,包免费重做(虚拟物品交付后不退款;未达承诺免费重做)。
👉 喵窝资源铺 · 服务下单 | 免费资源清单