python

关注公众号 jb51net

关闭
首页 > 脚本专栏 > python > Python操作Word目录

Python中Word文档目录创建、更新、提取与删除操作详解

作者:SunnyDays1011

在较长的 Word 文档中,目录通常是必不可少的内容,本文详细介绍了如何使用Python创建、插入、更新、提取和删除Word文档中的目录,有需要的小伙伴可以参考下

在报告、手册、方案书、技术文档等较长的 Word 文档中,目录通常是必不可少的内容。对于自动生成或批量更新的文档来说,手动插入或刷新目录不仅效率低,也容易遗漏。

借助 Python,可以自动完成 Word 目录相关操作,例如创建目录、在内容变更后更新目录、提取目录条目用于审阅,以及删除不再需要的旧目录。

本文将介绍如何使用 Python 在 Word 文档中插入、更新、提取和删除目录。

Word 目录的工作原理

Word 中的目录通常基于标题样式生成,例如:

当插入目录时,Word 会扫描文档中的标题段落,并根据标题级别生成对应的目录条目。

因此,在通过代码创建目录之前,需要确保要出现在目录中的段落使用的是真正的 Word 标题样式。仅仅将文字加粗或增大字号,并不能让 Word 将其识别为目录条目。

环境准备

要使用 Python 自动处理 Word 文档中的目录,可以使用 Free Spire.Doc for Python。该库可以在不安装 Microsoft Word 的情况下创建和编辑 Word 文档。

可以通过以下命令从 PyPI 安装:

pip install spire.doc.free

注意:该库要求 Python 3.7 或以上版本,请检查你系统中的 Python 版本。

使用 Python 创建带目录的 Word 文档

在 Word 文档中插入目录,可以使用 AppendTOC() 方法。该方法接收两个参数:

例如,AppendTOC(1, 3) 表示目录包含“标题 1”到“标题 3”。

下面的示例将创建一个新的 Word 文档,添加多个中文标题,插入目录,并将结果保存为 .docx 文件。

from spire.doc import *

# 创建一个新的 Word 文档
doc = Document()

# 设置中文字体
chinese_font = "Microsoft YaHei"

# 添加一个节
section = doc.AddSection()
section.PageSetup.Margins.All = 72

# 添加目录标题
toc_title = section.AddParagraph()
title_text = toc_title.AppendText("目录")
title_text.CharacterFormat.FontName = chinese_font
title_text.CharacterFormat.FontSize = 16
title_text.CharacterFormat.Bold = True

# 插入目录,包含“标题 1”到“标题 3”
toc_paragraph = section.AddParagraph()
toc_paragraph.AppendTOC(1, 3)

# 在目录后添加分页符,使正文从新的一页开始
toc_paragraph.AppendBreak(BreakType.PageBreak)

# 添加一级标题
paragraph = section.AddParagraph()
paragraph.ApplyStyle(BuiltinStyle.Heading1)
text = paragraph.AppendText("1. 引言")
text.CharacterFormat.FontName = chinese_font

# 添加正文内容
paragraph = section.AddParagraph()
text = paragraph.AppendText("本节介绍文档的编写目的、适用场景和背景信息。")
text.CharacterFormat.FontName = chinese_font

# 添加二级标题
paragraph = section.AddParagraph()
paragraph.ApplyStyle(BuiltinStyle.Heading2)
text = paragraph.AppendText("1.1 项目背景")
text.CharacterFormat.FontName = chinese_font

paragraph = section.AddParagraph()
text = paragraph.AppendText("本小节进一步说明项目背景、业务需求以及文档结构。")
text.CharacterFormat.FontName = chinese_font

# 添加另一个一级标题
paragraph = section.AddParagraph()
paragraph.ApplyStyle(BuiltinStyle.Heading1)
text = paragraph.AppendText("2. 实现方案")
text.CharacterFormat.FontName = chinese_font

paragraph = section.AddParagraph()
text = paragraph.AppendText("本节介绍文档处理流程、核心逻辑和实现方式。")
text.CharacterFormat.FontName = chinese_font

# 添加另一个二级标题
paragraph = section.AddParagraph()
paragraph.ApplyStyle(BuiltinStyle.Heading2)
text = paragraph.AppendText("2.1 处理逻辑")
text.CharacterFormat.FontName = chinese_font

paragraph = section.AddParagraph()
text = paragraph.AppendText("本小节说明程序如何识别标题、插入目录并更新目录内容。")
text.CharacterFormat.FontName = chinese_font

# 添加三级标题
paragraph = section.AddParagraph()
paragraph.ApplyStyle(BuiltinStyle.Heading3)
text = paragraph.AppendText("2.1.1 处理步骤")
text.CharacterFormat.FontName = chinese_font

# 更新目录
doc.UpdateTableOfContents()

# 保存文档
doc.SaveToFile("带目录的Word文档.docx", FileFormat.Docx2016)

# 关闭文档
doc.Close()

在上面的代码中,“目录”标题只是手动设置了字体、字号和加粗效果,并没有应用“标题 1”样式。

这是因为 Word 目录是根据标题样式生成的。如果将“目录”本身设置为标题样式,那么它也会被扫描并添加到目录中,导致目录中出现“目录”这一条目。

使用 Python 向现有 Word 文档插入目录

在实际项目中,很多时候 Word 文档已经存在,只需要在文档开头插入目录即可。

下面的示例加载一个现有 Word 文档,在第一节开头插入目录标题和目录字段,然后更新目录并保存结果。

from spire.doc import *

# 加载现有 Word 文档
doc = Document()
doc.LoadFromFile("示例文档.docx")

# 设置中文字体
chinese_font = "Microsoft YaHei"

# 获取第一个节
section = doc.Sections[0]

# 在节的开头添加目录标题
title_paragraph = Paragraph(doc)
title_text = title_paragraph.AppendText("目录")
title_text.CharacterFormat.FontName = chinese_font
title_text.CharacterFormat.FontSize = 16
title_text.CharacterFormat.Bold = True
section.Paragraphs.Insert(0, title_paragraph)

# 在标题下方添加目录字段
toc_paragraph = Paragraph(doc)
toc_paragraph.AppendTOC(1, 3)
section.Paragraphs.Insert(1, toc_paragraph)

# 在目录后添加分页符
toc_paragraph.AppendBreak(BreakType.PageBreak)

# 更新目录
doc.UpdateTableOfContents()

# 保存结果文档
doc.SaveToFile("插入目录后的文档.docx", FileFormat.Docx2016)

# 关闭文档
doc.Close()

该示例会将目录插入到第一个节的开头。如果文档包含封面、前言或其他前置内容,可以根据实际结构调整插入位置,或者单独创建一个新的节用于放置目录。

需要注意的是,现有文档中应当已经使用了真正的 Word 标题样式。如果文档中的标题只是通过加粗、增大字号等方式手动设置的,目录可能为空或不完整。

使用 Python 更新 Word 目录

更新目录指的是根据当前文档中的标题内容重新刷新目录条目和页码。

下面的示例加载一个已经包含目录的 Word 文档,修改其中一个标题,然后更新目录。

from spire.doc import *

# 加载一个已经包含目录的 Word 文档
doc = Document()
doc.LoadFromFile("带目录的Word文档.docx")

# 修改目录中对应的标题文本
doc.Replace("1. 引言", "1. 更新后的引言", True, True)

# 更新目录
doc.UpdateTableOfContents()

# 保存更新后的文档
doc.SaveToFile("更新目录后的文档.docx", FileFormat.Docx2016)

# 关闭文档
doc.Close()

当文档内容、标题文本或标题位置发生变化后,应调用 UpdateTableOfContents() 方法刷新目录,确保目录条目和页码与正文内容保持一致。

使用 Python 提取 Word 目录条目

Word 中的目录通常有两种形式:

存储在 StructureDocumentTag 中的目录段落,比如在 Word 中手动添加的目录:

目录段落,比如本文中以编程方式插入的目录。

下面的示例会同时处理这两种情况。它会提取 Word 文档中的目录条目,并保存到文本文件中。输出结果会保留目录内容,并根据目录级别添加缩进,便于查看层级结构。

import re
from spire.doc import *

# 创建 Document 对象
doc = Document()

# 加载包含目录的 Word 文档
doc.LoadFromFile("带目录的Word文档.docx")

# 用于存储提取到的目录条目
toc_entries = []

def get_toc_level(paragraph):
    """
    根据段落样式名称获取目录级别。
    例如:TOC1、TOC2、TOC3、TOC 1、TOC 2。
    """
    style_name = paragraph.StyleName

    if style_name is None:
        return None

    match = re.match(r"^TOC\s*(\d+)$", style_name.strip(), re.IGNORECASE)

    if match:
        return int(match.group(1))

    return None

def extract_toc_entry(paragraph):
    """
    从目录段落中提取文本。
    """
    level = get_toc_level(paragraph)

    if level is None:
        return

    text = paragraph.Text.strip()

    if not text:
        return

    # 根据目录级别添加缩进
    indent = "    " * (level - 1)
    toc_entries.append(indent + text)

# 遍历文档中的所有节
for s in range(doc.Sections.Count):
    section = doc.Sections.get_Item(s)
    body = section.Body

    # 遍历节正文中的所有子对象
    for i in range(body.ChildObjects.Count):
        obj = body.ChildObjects.get_Item(i)

        # 如果目录存储在 StructureDocumentTag 中
        if isinstance(obj, StructureDocumentTag):
            tag = obj

            # 遍历目录容器中的段落
            for j in range(tag.ChildObjects.Count):
                child_obj = tag.ChildObjects.get_Item(j)

                if isinstance(child_obj, Paragraph):
                    extract_toc_entry(child_obj)

        # 如果目录以普通段落和 TOC 样式存储
        elif isinstance(obj, Paragraph):
            paragraph = obj
            extract_toc_entry(paragraph)

# 将提取到的目录条目保存到文本文件
with open("提取的目录.txt", "w", encoding="utf-8") as file:
    for entry in toc_entries:
        file.write(entry + "\n")

# 关闭文档
doc.Close()

提取的目录内容如下所示:

1. 引言    2
    1.1 项目背景    2
2. 实现方案    2
    2.1 处理逻辑    2
        2.1.1 处理步骤    2

这种输出方式保留了原始 Word 目录的层级结构,因此更便于查看和校对。

如果只想保留目录标题,不需要页码,可以将 extract_toc_entry() 函数中的这行代码:

text = paragraph.Text.strip()

替换为:

# 移除目录条目末尾的页码
text = re.sub(r"[\t ]+\d+\s*$", "", paragraph.Text).strip()

处理后的输出如下所示:

1. 引言
    1.1 项目背景
2. 实现方案
    2.1 处理逻辑
        2.1.1 处理步骤

使用 Python 删除 Word 目录

删除目录的逻辑与提取目录类似。先定位目录内容,再根据其存储形式进行删除。目录可能存储在 StructureDocumentTag 中,也可能是使用 TOC1TOC2TOC3 等目录样式的普通段落。

下面的示例会同时删除这两类目录内容,并移除手动添加的目录标题。

import re
from spire.doc import *

# 创建 Document 对象
doc = Document()

# 加载包含目录的 Word 文档
doc.LoadFromFile("带目录的Word文档.docx")

# 匹配目录段落样式,例如 TOC1、TOC2、TOC3、TOC 1、TOC 2
toc_style_pattern = r"^TOC\s*\d+$"

def is_toc_paragraph(paragraph):
    """
    判断段落是否为目录条目。
    """
    style_name = paragraph.StyleName or ""
    return re.match(toc_style_pattern, style_name.strip(), re.IGNORECASE) is not None

def is_toc_title(paragraph):
    """
    判断段落是否为手动添加的目录标题。
    """
    title = paragraph.Text.strip().lower()
    return title in ("目录", "table of contents")

def contains_toc_paragraph(tag):
    """
    判断 StructureDocumentTag 中是否包含目录段落。
    """
    for i in range(tag.ChildObjects.Count):
        child_obj = tag.ChildObjects.get_Item(i)

        if isinstance(child_obj, Paragraph) and is_toc_paragraph(child_obj):
            return True

    return False

# 遍历文档中的所有节
for s in range(doc.Sections.Count):
    section = doc.Sections.get_Item(s)
    body = section.Body

    i = 0
    while i < body.ChildObjects.Count:
        obj = body.ChildObjects.get_Item(i)

        # 删除存储在 StructureDocumentTag 中的目录
        if isinstance(obj, StructureDocumentTag):
            tag = obj

            if contains_toc_paragraph(tag):
                body.ChildObjects.RemoveAt(i)
                continue

        # 删除目录条目或手动添加的目录标题
        elif isinstance(obj, Paragraph):
            paragraph = obj

            if is_toc_paragraph(paragraph) or is_toc_title(paragraph):
                body.ChildObjects.RemoveAt(i)
                continue

        i += 1

# 保存删除目录后的文档
doc.SaveToFile("删除目录后的Word文档.docx", FileFormat.Docx2016)

# 关闭文档
doc.Close()

这段代码不仅会删除目录条目,也会删除手动添加的目录标题,例如“目录”或“Table of Contents”。

常见问题与解决方法

1. 生成的目录为空

这通常是因为文档没有使用真正的 Word 标题样式。请确保需要加入目录的段落使用了内置标题样式,例如“标题 1”“标题 2”或“标题 3”。

2. “目录”标题出现在目录条目中

如果“目录”这个标题本身被设置为“标题 1”或其他标题样式,就会被加入目录。为了避免这种情况,可以手动设置其字体、字号和加粗效果,而不要对其应用标题样式。

3. 目录中的页码不正确

在添加、删除或修改文档内容后,需要调用 UpdateTableOfContents() 方法刷新目录。这样可以更新目录条目和对应页码。

4. 部分标题没有出现在目录中

请检查插入目录时设置的标题级别范围。例如,AppendTOC(1, 2) 只会包含“标题 1”和“标题 2”。如果需要包含“标题 3”,应使用 AppendTOC(1, 3)

5. 中文字体显示不正确

如果生成的 Word 文档中中文字体显示异常,可以在添加文本时显式设置支持中文的字体,例如:

text.CharacterFormat.FontName = "Microsoft YaHei"

如果在 Linux 或服务器环境中运行代码,请确保系统已安装相应中文字体。也可以根据实际环境将字体替换为 宋体、Arial Unicode MS 等可用的中文字体。

总结

本文介绍了如何使用 Python 创建、插入、更新、提取和删除 Word 文档中的目录。通过这些方法,可以更方便地维护自动生成的报告、手册、方案书和技术文档,使长文档的结构更加清晰,也便于读者快速导航。

以上就是Python中Word文档目录创建、更新、提取与删除操作详解的详细内容,更多关于Python操作Word目录的资料请关注脚本之家其它相关文章!

您可能感兴趣的文章:
阅读全文