视频教程:Python通过win32com库操作Word教程_哔哩哔哩_bilibili
如果需要原Jupyter notebook文件和用作示例的图片、文档,可以联系我。
引言
在 Python 生态中,操作 Word 文档的库有不少,比如 python-docx 主要处理 .docx 格式,而 win32com(即 pywin32)则提供了更为底层的控制能力——它直接调用微软 Office 的 COM 接口,这意味着你的 Word 软件能做什么,win32com 就能做什么。不仅可以读写文本,还能操作表格、图表、域代码、目录、格式转换,甚至执行查找替换等复杂任务。
不过,使用它也有一些前提和限制:
- 只能在 Windows 系统上运行,并且必须已安装 Microsoft Word(WPS 或其他打开 Word 的软件不行)。
- 默认情况下,代码是单线程的。
- 操作完成后,务必记得关闭 Word 客户端(
doc.Close()和word.Quit()),否则 Word 进程会一直留在后台,需要手动从任务管理器结束。
win32com 其实是一个通用 COM 客户端,不仅能操作 Word,还能操作 Excel、PPT、Outlook 等微软软件。本文只聚焦于 Word 的操作。
通过python-docx、docxtpl、Composer库处理Word文档的教程请参考:Python处理Word文档完全指南:从基础到进阶
安装
pip install pywin32
如果遇到常数(constants)加载异常(例如无法使用 constants.wdReplaceAll),可以尝试强制重新生成缓存:
import win32com.client as win32
word = win32.gencache.EnsureDispatch('Word.Application') # 替换win32.Dispatch()接口
或者手动删除缓存文件夹(通常在 %temp%\gen_py 下,例如 C:\Users\用户名\AppData\Local\Temp\gen_py)。
基础概念
在深入代码之前,先了解几个核心对象:
| 对象 | 说明 |
|---|---|
Application | Word 应用程序本身,通过 win32.Dispatch 获得 |
Document | 代表一个打开的文档,通过 Documents.Add 或 Documents.Open 获取 |
Selection | 当前光标选中的区域(或光标位置) |
Range | 文档中的一个连续区域(可以不是选中状态) |
Paragraph | 段落,由回车符分隔 |
Font / ParagraphFormat | 字体和段落格式 |
1. 新建文档并写入文字
使用 Range 对象
import win32com.client as win32
word = win32.Dispatch("Word.Application")
word.Visible = True # True 会显示 Word 界面(但很快消失)
doc = word.Documents.Add()
range_obj = doc.Range(0, 0)
range_obj.InsertAfter("Hello World from Python!")
# 注意:必须使用绝对路径,否则会保存到 Word 的默认文件夹
doc.SaveAs(r"D:\your_path\test.docx")
doc.Close()
word.Quit()
使用 Selection 对象(模拟光标)
word = win32.Dispatch("Word.Application")
word.Visible = False
doc = word.Documents.Add()
selection = word.Selection
selection.TypeText("Hello, World!")
selection.TypeParagraph() # 换行(新段落)
selection.TypeText("这是第二行")
doc.SaveAs(r"D:\your_path\test.docx")
doc.Close()
word.Quit()
注意:
Range是一个独立区域,不依赖光标;Selection则代表当前光标位置,常用于模拟用户操作。
2. 打开文档,读取内容并追加文字
word = win32.Dispatch("Word.Application")
word.Visible = False
doc = word.Documents.Open(r"D:\your_path\test.docx")
# 遍历所有段落打印内容
for paragraph in doc.Paragraphs:
print(paragraph.Range.Text)
# 在文档末尾追加内容
doc.Content.InsertAfter("\n这是新增的内容")
doc.Close()
word.Quit()
注意:直接使用
doc.Content.Text获取全文有时会返回异常结果(如只得到这是第二行, World!),所以推荐遍历段落。
3. 设置字体与段落格式
误区:使用 Selection 设置字体无效
selection = word.Selection
# 字体设置无效
selection.Font.Name = "微软雅黑"
selection.Font.Size = 16
selection.Font.Bold = True
selection.Font.ColorIndex = 6 # 红色
# 段落设置有效
selection.ParagraphFormat.Alignment = 1 # 居中(0左 1中 2右 3两端)
selection.ParagraphFormat.LineSpacingRule = 0 # 单倍行距
原因:Selection 只是一个点,设置字体需要作用于一个区域。
正确方法:使用 Range 设置整个文档
range_obj = doc.Content
range_obj.Font.Name = "微软雅黑"
range_obj.Font.Size = 16
range_obj.Font.Bold = True
range_obj.Font.ColorIndex = 6
range_obj.ParagraphFormat.Alignment = 1
range_obj.ParagraphFormat.LineSpacingRule = 0
设置标题样式
range_obj = doc.Range(0, 0)
range_obj.Text = "第一章 概述"
range_obj.Style = doc.Styles("标题 1") # 英文版可能是 "Heading 1"
4. 插入表格
range_obj = doc.Content
range_obj.Collapse(0) # 0 折叠到末尾,1 折叠到开头
table = doc.Tables.Add(range_obj, NumRows=3, NumColumns=3)
# 单元格索引从 1 开始
table.Cell(1,1).Range.Text = "姓名"
table.Cell(1,2).Range.Text = "年龄"
table.Cell(1,3).Range.Text = "结果"
table.Cell(2,1).Range.Text = "张三"
table.Cell(2,2).Range.Text = "25"
table.Cell(2,3).Range.Text = "合格"
5. 查找与替换
简单替换(全文匹配)
find = word.Selection.Find
find.Text = "{{name}}"
find.Replacement.Text = "张三"
find.Execute(Replace=2) # Replace=2 表示全部替换
处理缓存异常问题
缓存异常的显著表现是无法导入 constants ,同时查找和替换功能也会出现异常。可以显式设置所有参数来解决问题:
WD_FIND_CONTINUE = 1 # 继续查找
WD_REPLACE_ALL = 2 # 全部替换
rng = doc.Content
for old, new in [("{{name}}", "张三"), ("{{date}}", "2026-02-26")]:
rng.Find.Execute(
old, False, False, False, False, False,
True, WD_FIND_CONTINUE, False, new, WD_REPLACE_ALL
)
rng = doc.Content # 重新获取 Range,避免被移动
6. 插入图片
range_obj = doc.Content
range_obj.Collapse(0) # 移动到末尾
doc.InlineShapes.AddPicture(
r"D:\your_path\pic1.jpeg",
False, True, range_obj
)
7. 更新目录
for toc in doc.TablesOfContents:
toc.Update()
8. Word 转 PDF 及 doc/docx 互转
doc.ExportAsFixedFormat(
OutputFileName=r"D:\your_path\test.pdf",
ExportFormat=17 # 17 代表 PDF;16 代表 docx;0/1 代表 doc
)
笔者曾基于此功能开发过一个桌面工具,支持 Word/PDF 互转及 Excel 格式互转,详情参考:如何用Python处理文件:Word导出PDF 和 doc / docx互相转换。
9. 插入域代码:以日期域为例
range_obj = doc.Content
range_obj.Collapse(0)
field = doc.Fields.Add(
Range=range_obj,
Type=31 # wdFieldDate
)
# 等价写法(插入空域,再指定代码)
# field = doc.Fields.Add(
# Range=range_obj,
# Type=constants.wdFieldEmpty,
# Text="DATE \\* MERGEFORMAT"
# )
10. 实例:将纯文本图标签替换为 SEQ 域
原始文档:包含“图 1”、“图 2”等纯文本
目标:替换为域代码 图 { SEQ 图 \* ARABIC },实现自动编号。
word = win32.gencache.EnsureDispatch('Word.Application')
word.Visible = False
doc = word.Documents.Open(r"D:\your_path\instance1.docx")
search_range = doc.Range()
search_range.Find.Text = "图 [0-9]{1,}"
search_range.Find.Wrap = 0 # wdFindStop,不循环
search_range.Find.MatchWildcards = True # 通配符匹配
found = search_range.Find.Execute()
while found:
insert_point = search_range.Duplicate # 复制当前 Range
insert_point.Delete() # 删除原文本
insert_point.InsertAfter("图 ") # 插入“图 ”
insert_point.Collapse(Direction=0) # 折叠到末尾
# 插入 SEQ 域
seq_code = 'SEQ 图 \\* ARABIC'
doc.Fields.Add(insert_point, -1, seq_code, False) # -1 代表 wdFieldEmpty
search_range.Collapse(Direction=0)
found = search_range.Find.Execute()
doc.Fields.Update()
doc.SaveAs(r"D:\your_path\test.docx")
doc.Close()
word.Quit()
11. 复杂实例:带章节号的图标签(如 图 1-1、图 1-2)
原始文档:包含“图 1-1”、“图 1-2”等纯文本
目标:替换为 图 { STYLEREF 1 \s }-{ SEQ 图 \* ARABIC \s 1 },其中章节号来自标题1(一级标题)的编号。
word = win32.Dispatch("Word.Application")
word.Visible = False
doc = word.Documents.Open(r"D:\your_path\instance2.docx")
search_range = doc.Range()
search_range.Find.Text = "图 [0-9]{1,}-[0-9]{1,}"
search_range.Find.Wrap = constants.wdFindStop
search_range.Find.MatchWildcards = True
found = search_range.Find.Execute()
while found:
insert_point = search_range.Duplicate
insert_point.Delete()
insert_point.InsertAfter("图 ")
insert_point.Collapse(Direction=constants.wdCollapseEnd)
# 插入 STYLEREF 域
styleref_code = 'STYLEREF 1 \\s'
field_styleref = doc.Fields.Add(insert_point, constants.wdFieldEmpty, styleref_code, False)
field_styleref.Update()
# 将光标移动到域之后
field_styleref.Select()
word.Selection.Collapse(Direction=constants.wdCollapseEnd)
insert_point = word.Selection.Range.Duplicate
# 插入连字符
insert_point.InsertAfter("-")
insert_point.Collapse(Direction=constants.wdCollapseEnd)
# 插入 SEQ 域
seq_code = 'SEQ 图 \\* ARABIC \\s 1'
doc.Fields.Add(insert_point, constants.wdFieldEmpty, seq_code, False)
search_range.Collapse(Direction=constants.wdCollapseEnd)
found = search_range.Find.Execute()
doc.Fields.Update()
doc.SaveAs(r"D:\your_path\test.docx")
doc.Close()
word.Quit()
关键点:
- 使用
Duplicate复制 Range,避免原对象被后续操作改变。- 插入域后需要先更新域(
Update()),然后选中它再折叠,才能准确定位到域之后的位置。- 这些技巧在插入复杂域时非常重要。
总结
win32com 是操作 Word 的强大工具,几乎可以实现 VBA 能做的所有事情。本文涵盖了从新建文档、格式设置、表格、查找替换、图片、目录、格式转换到域代码操作等常见需求。虽然它有平台限制(仅 Windows + 已安装Word软件),但对于需要深度控制 Word 文档的自动化任务来说,它是不可或缺的利器。