我的知识记录

Python Word生成目录:自动插入TOC域

用python-docx在Word文档开头插入自动目录域(TOC field),打开后右键更新即可生成页码,配合Heading样式批量生成报告目录。

场景痛点

长文档写完,最后要加目录。手动敲"第一章……1"然后填页码,一改章节页码全乱。Word自带的"引用-目录"功能虽然自动,但批量生成几十份报告时还是得每份点一下。用Python直接往文档里插一个TOC域,打开文档按F9就自动生成目录,页码实时更新。

用到的库

pip install python-docx

完整代码

# -*- coding: utf-8 -*-
"""
在 Word 文档开头插入自动目录(TOC 域)
"""
from pathlib import Path
from docx import Document
from docx.oxml.ns import qn
from docx.oxml import OxmlElement


def add_toc(doc, levels="1-3", title="目  录"):
"""
在文档最前面插入:标题 + TOC 域
levels: 目录收集的标题级别,如 "1-3" 表示一到三级标题
"""
# 目录标题
heading_para = doc.add_paragraph(title)
# 设置目录标题居中(简单设置)
from docx.enum.text import WD_ALIGN_PARAGRAPH
heading_para.alignment = WD_ALIGN_PARAGRAPH.CENTER

# 新建一个段落,用来放 TOC 域
para = doc.add_paragraph()
run = para.add_run()

# 构造 fldChar begin
fldChar1 = OxmlElement('w:fldChar')
fldChar1.set(qn('w:fldCharType'), 'begin')

# 构造 instrText,写 TOC 域指令
instrText = OxmlElement('w:instrText')
instrText.set(qn('xml:space'), 'preserve')
instrText.text = f' TOC \\o "{levels}" \\h \\z \\u '

# fldChar separate
fldChar2 = OxmlElement('w:fldChar')
fldChar2.set(qn('w:fldCharType'), 'separate')

# 占位文字(在 Word 更新域之前显示)
placeholder = OxmlElement('w:t')
placeholder.text = "右键点击此处,选择"更新域"以生成目录。"

# fldChar end
fldChar3 = OxmlElement('w:fldChar')
fldChar3.set(qn('w:fldCharType'), 'end')

# 按顺序塞进 run
run._r.append(fldChar1)
run._r.append(instrText)
run._r.append(fldChar2)
run._r.append(placeholder)
run._r.append(fldChar3)


def build_demo_doc():
"""造一个带标题的演示文档"""
doc = Document()
doc.add_heading("项目立项报告", level=0)

doc.add_heading("一、项目背景", level=1)
doc.add_paragraph("项目背景内容……")
doc.add_heading("1.1 行业现状", level=2)
doc.add_paragraph("行业现状内容……")
doc.add_heading("1.2 公司情况", level=2)
doc.add_paragraph("公司情况内容……")

doc.add_heading("二、技术方案", level=1)
doc.add_paragraph("技术方案内容……")
doc.add_heading("2.1 架构设计", level=2)
doc.add_paragraph("架构设计内容……")

doc.add_heading("三、预算与排期", level=1)
doc.add_paragraph("预算内容……")

# 在文档最前面插目录
add_toc(doc, levels="1-2", title="目  录")

out = Path("./report_with_toc.docx")
doc.save(str(out))
print(f"已生成:{out}")
print("用 Word 打开后,右键目录区域 -> 更新域 -> 更新整个目录,即可看到页码。")


if __name__ == "__main__":
build_demo_doc()

代码讲解

python-docx 没有直接的"插入目录"方法,因为目录本质是一个Word域(field)。所以用 OxmlElement 手工拼XML:w:fldChar begin 标记域开始,w:instrText 里写域指令 TOC \o "1-3" \h \z \uw:fldChar end 标记结束。

域指令参数含义:\o "1-3" 收集1到3级标题,\h 超链接,\z 隐藏Web视图的前导符,\u 使用大纲级别。中间放一段占位文字,在Word还没更新域时能看到提示。

add_toc()doc.add_paragraph() 追加到文档末尾,再把它移到开头——更简单的做法是直接把目录放在文档末尾,然后整篇文档通过"前后交换"或者把add_toc在add_heading之前调用。本演示是先add正文再add_toc,实际使用时应该先add_toc再add正文。

运行结果

打开 report_with_toc.docx,开头有"目录"标题和一段提示文字。右键目录区域选"更新域"->"更新整个目录",目录立刻展开成"一、项目背景……1"这种带页码的形式。以后改了内容页码变了,再按一次F9即可。

注意事项

  • python-docx 生成的TOC域在Word里是"未计算"状态,必须打开Word按F9或右键更新才会显示页码。这是正常的,不是bug。WPS同理。
  • 目录只收应用了"标题1/标题2"样式(或大纲级别)的段落,正文段落不会进目录。
  • 如果想打开文档自动更新目录,需要设置文档属性,但这个python-docx做不到,建议在Word里另存一次或者告诉用户按F9。
  • levels 参数控制收几级,报告一般"1-2"或"1-3"就够,别开"1-9"否则把正文都收进去。

Python Word生成目录:自动插入TOC域

标签:

更新时间:2026-09-14 21:48:40

上一篇:Python Word页眉页脚设置教程

下一篇: