当前位置:首页>python>第338讲:分别用 VBA 和 Python(python-docx) 来实现:Excel数据批量生成Word文档(合同/工单)

第338讲:分别用 VBA 和 Python(python-docx) 来实现:Excel数据批量生成Word文档(合同/工单)

  • 2026-09-08 19:24:25
第338讲:分别用 VBA 和 Python(python-docx) 来实现:Excel数据批量生成Word文档(合同/工单)

场景:从员工信息表批量生成入职合同或工单

在日常办公中,HR、行政、运营同学最常遇到的一个痛点就是:Excel里有一堆数据,却要一个个复制到Word模板里生成合同、工单、通知书。手工操作不仅慢,还容易出错。很多人知道可以用Word的“邮件合并”,但一旦模板复杂(比如带条件判断、动态表格、不同条款),邮件合并就显得力不从心。

今天这讲,我会从实战角度,分别用 VBA 和 Python(python-docx) 来实现“从Excel批量生成Word文档”。不只告诉你怎么做,还会对比两者背后的对象模型差异,让你真正理解“什么时候该用VBA,什么时候该用Python”。


一、典型业务场景说明

假设你是HR,手上有这样一张Excel员工信息表(employee.xlsx):

工号

姓名

部门

岗位

入职日期

合同期限(年)

月薪

1001

张三

技术部

后端工程师

2025-03-01

3

18000

1002

李四

产品部

产品经理

2025-03-05

2

16000

你需要根据这个表,批量生成入职劳动合同(Word版),每个员工一个文件,命名规则为:工号_姓名_劳动合同.docx。

Word模板(contract_template.docx)中有若干占位符,例如:

员工姓名:{{姓名}}
所属部门:{{部门}}
合同期限:{{合同期限}}年
……

下面我们分别用两种技术方案实现。


二、VBA方案:Word.Application + 书签替换

1. 为什么用“书签”而不是“查找替换”

很多VBA初学者会用 Selection.Find.Execute做全文替换,但在正式合同中不推荐,原因有三:

  1. 误伤风险:如果正文里恰好出现和占位符相同的文字,会被错误替换。

  2. 格式不稳定:查找替换容易打乱原有字体、加粗、段落格式。

  3. 无法精确定位:合同往往有多个章节,需要精确控制位置。

书签(Bookmark)是Word对象模型中专门用于“标记位置”的对象,非常适合做结构化填充。


2. Word模板准备(关键一步)

在Word模板中:

  1. 选中要填充的位置(如“张三”处)。

  2. 「插入」→「书签」。

  3. 输入书签名,如 bm_name、bm_department。

  4. 注意:书签名不能重复,不能有空格。

一个规范的合同模板,书签设计通常如下:

书签名

含义

bm_id

工号

bm_name

姓名

bm_dept

部门

bm_position

岗位

bm_start

入职日期

bm_years

合同期限

bm_salary

月薪


3. VBA代码实现(逐行注释)

在Excel中按 Alt + F11,插入 → 模块,粘贴以下代码:

Sub BatchGenerateContracts()    Dim wdApp As Object    Dim wdDoc As Object    Dim wb As Workbook    Dim ws As Worksheet    Dim lastRow As Long    Dim i As Long    Dim templatePath As String    Dim savePath As String    ' 模板路径和保存路径(务必修改成你自己的)    templatePath = "C:\Templates\contract_template.docx"    savePath = "C:\Contracts\"    ' 当前工作簿和工作表    Set wb = ThisWorkbook    Set ws = wb.Sheets("Sheet1")    ' 创建Word应用    On Error Resume Next    Set wdApp = CreateObject("Word.Application")    If wdApp Is Nothing Then        MsgBox "无法创建Word应用,请确认已安装Microsoft Word。"        Exit Sub    End If    On Error GoTo 0    wdApp.Visible = False ' 后台运行,速度快    ' 找到最后一行    lastRow = ws.Cells(ws.Rows.Count, 1).End(xlUp).Row    ' 遍历每一行员工数据    For i = 2 To lastRow        ' 打开模板        Set wdDoc = wdApp.Documents.Open(templatePath)        ' 替换书签内容        With wdDoc.Bookmarks            .Item("bm_id").Range.Text = ws.Cells(i, 1).Value            .Item("bm_name").Range.Text = ws.Cells(i, 2).Value            .Item("bm_dept").Range.Text = ws.Cells(i, 3).Value            .Item("bm_position").Range.Text = ws.Cells(i, 4).Value            .Item("bm_start").Range.Text = Format(ws.Cells(i, 5).Value, "yyyy年mm月dd日")            .Item("bm_years").Range.Text = ws.Cells(i, 6).Value            .Item("bm_salary").Range.Text = ws.Cells(i, 7).Value        End With        ' 保存为新文件        wdDoc.SaveAs2 savePath & ws.Cells(i, 1).Value & "_" & ws.Cells(i, 2).Value & "_劳动合同.docx"        ' 关闭当前文档,不保存模板        wdDoc.Close SaveChanges:=False    Next i    ' 退出Word    wdApp.Quit    Set wdDoc = Nothing    Set wdApp = Nothing    MsgBox "批量生成完成!共生成 " & lastRow - 1 & " 份合同。"End Sub

4. VBA方案的优缺点总结

优点:

  • 无需安装额外环境,Office自带。

  • 对Word格式控制极其精细(字体、段落、表格、页眉页脚)。

  • 适合在纯Windows + Office环境下的企业内部使用。

缺点:

  • 只能在Windows运行,Mac版Excel对VBA支持不完整。

  • 代码可维护性一般,复杂逻辑写起来冗长。

  • 对非技术人员不友好,“宏被禁用”是常见问题。


三、Python方案:python-docx 库 + 占位符替换

当你面对的是跨平台、自动化流水线,或者模板逻辑较复杂时,Python是更好的选择。

1. 环境准备

pip install python-docx pandas openpyxl
  • python-docx:操作Word文档

  • pandas:读取Excel

  • openpyxl:Excel引擎


2. Word模板设计(占位符法)

不同于VBA的书签,Python-docx对书签支持并不友好,业界常用做法是占位符替换。

在Word模板中使用双大括号占位符:

员工姓名:{{name}}
所属部门:{{dept}}
合同期限:{{years}}年
月薪:{{salary}}元

这种写法直观、易维护,也方便非程序员理解。


3. Python核心实现代码

import pandas as pdfrom docx import Documentimport osfrom datetime import datetime# 路径配置EXCEL_PATH = r"C:\data\employee.xlsx"TEMPLATE_PATH = r"C:\templates\contract_template.docx"SAVE_DIR = r"C:\contracts"# 读取Exceldf = pd.read_excel(EXCEL_PATH)# 确保保存目录存在os.makedirs(SAVE_DIR, exist_ok=True)def replace_text_in_paragraph(paragraph, placeholders):    """    替换单个段落中的占位符    """    for key, value in placeholders.items():        if f"{{{{{key}}}}}" in paragraph.text:            # 保留原有格式            inline = paragraph.runs            for run in inline:                run.text = run.text.replace(f"{{{{{key}}}}}", str(value))def generate_contract(row):    """    生成单个合同    """    doc = Document(TEMPLATE_PATH)    # 构造占位符字典    placeholders = {        "id": str(row["工号"]),        "name": row["姓名"],        "dept": row["部门"],        "position": row["岗位"],        "start": row["入职日期"].strftime("%Y年%m月%d日"),        "years": str(row["合同期限(年)"]),        "salary": f"{row['月薪']:,}"    }    # 遍历所有段落    for para in doc.paragraphs:        replace_text_in_paragraph(para, placeholders)    # 处理表格中的占位符(合同常包含表格)    for table in doc.tables:        for row_table in table.rows:            for cell in row_table.cells:                for para in cell.paragraphs:                    replace_text_in_paragraph(para, placeholders)    # 保存文件    filename = f"{row['工号']}_{row['姓名']}_劳动合同.docx"    filepath = os.path.join(SAVE_DIR, filename)    doc.save(filepath)    print(f"已生成:{filename}")# 批量生成for idx, row in df.iterrows():    generate_contract(row)print("全部合同生成完成。")

4. Python方案的进阶技巧

(1)条件条款渲染

有些合同条款是有条件的,例如:

if row["合同期限(年)"] >= 3:    placeholders["clause"] = "本合同包含长期服务奖金条款。"else:    placeholders["clause"] = ""

(2)动态表格行

python-docx支持动态添加表格行,非常适合工单、明细表:

table = doc.tables[0]new_row = table.add_row()new_row.cells[0].text = "加班费"new_row.cells[1].text = "2000"

(3)与自动化流程集成

Python脚本可以轻松接入:

  • Windows任务计划程序

  • Jenkins / GitLab CI

  • 企业微信机器人回调

这是VBA难以做到的。


5. Python方案的优缺点总结

优点:

  • 跨平台(Windows / macOS / Linux)。

  • 代码可读性强,逻辑清晰,易维护。

  • 可结合Pandas做复杂数据处理。

  • 易于与企业自动化系统对接。

缺点:

  • 需要安装Python环境(对非技术团队有门槛)。

  • 对Word高级格式(如文本框、页眉页脚深层嵌套)支持不如VBA直接。

  • 不支持直接调用Word“邮件合并”引擎。


四、核心对照:python-docx vs VBA Word对象模型

这是本讲的精华部分,建议反复阅读。

维度

VBA + Word对象模型

Python + python-docx

运行环境

Windows + Office

跨平台 + Python

模板机制

书签(Bookmark)

占位符({{key}})

格式控制

⭐⭐⭐⭐⭐(原生支持)

⭐⭐⭐⭐(依赖run层级)

表格操作

非常成熟

成熟,但略繁琐

条件逻辑

支持,但语法冗长

支持,Python原生逻辑清晰

错误处理

On Error Resume Next

try/except,结构清晰

自动化集成

弱(依赖Office)

强(命令行、API、CI)

学习曲线

对Office用户友好

对开发者友好

一句话总结:

**如果你在Windows上,只和Word打交道,选VBA;

如果你要做自动化、跨平台、复杂逻辑,选Python。**


五、实战选型建议

在实际工作中,我通常这样建议团队:

  1. 行政/HR单机使用:

    用VBA,一键按钮搞定,不需要IT介入。

  2. IT/数据分析团队:

    用Python,方便版本管理、复用和自动化。

  3. 混合模式(推荐):

    Excel作为前端录入界面,Python作为后台引擎,通过“生成按钮 → 调用Python脚本”的方式结合两者优势。


六、常见坑位提醒

  1. VBA书签删除后不会自动恢复:替换一次后书签会消失,若需多次使用,需复制模板再操作。

  2. python-docx不能直接编辑页眉页脚中的占位符:需要单独遍历 doc.sections。

  3. 路径问题:Windows路径建议加 r""原始字符串,避免转义错误。

  4. Excel日期类型:Python读取后要显式 .strftime(),否则可能变成浮点数。

七、练习题(巩固本讲内容)

第338讲课后练习(选择题)

  1. 在VBA批量生成Word文档时,相比“查找替换”,使用“书签(Bookmark)”的主要优势不包括以下哪项?

    A. 精确定位填充位置

    B. 避免误替换正文相似文字

    C. 可以直接调用Python脚本

    D. 更好保留原有格式

  2. 使用python-docx进行占位符替换时,为什么通常需要遍历 paragraph.runs?

    A. runs代表不同的页面

    B. runs保存了字符级格式信息,直接替换paragraph.text会丢失格式

    C. runs是Word中的图片对象

    D. runs等同于书签

  3. 以下关于VBA方案的说法,正确的是?

    A. VBA代码可以在macOS版Excel中无缝运行

    B. VBA可以直接操作Word的所有对象模型

    C. VBA不适合任何批量文档生成场景

    D. VBA无需任何模板即可生成格式复杂的合同

  4. 如果一个Word合同模板中包含多个表格,Python代码需要如何处理才能替换表格内的占位符?

    A. 只需替换paragraphs即可

    B. 必须遍历doc.tables,并逐个cell、paragraph处理

    C. python-docx不支持表格操作

    D. 只能通过VBA实现

  5. 在企业自动化场景中,Python方案相比VBA的最大优势是?

    A. 不需要安装任何软件

    B. 更容易与CI/CD、定时任务、API系统集成

    C. 比VBA运行速度更快

    D. 可以直接修改Excel公式


八、参考答案

  1. C

  2. B

  3. B

  4. B

  5. B


最新文章

随机文章