You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多
文档控制台
免费开始使用

如何用python-docx提取Docx标题间内容并维护标题层级

搞定这个问题其实不难!你已经迈出了第一步——成功提取标题,接下来只需要跟踪标题层级,把每个标题对应的内容(直到下一个同级/更高级标题)关联起来就行。我给你一套实用的方案:

核心思路

我们可以遍历文档的所有段落,用一个列表跟踪当前的标题层级路径(比如[一级标题, 二级标题]):

  • 遇到标题时,先调整层级路径(弹出比当前层级高的标题),然后把当前标题加到对应父标题的子节点里
  • 遇到普通段落时,直接把它加到当前最内层标题的内容列表中

完整代码实现

from docx import Document

def build_document_structure(doc_path):
    doc = Document(doc_path)
    # 最终的文档结构,根节点是一级标题列表
    doc_structure = []
    # 跟踪当前所处的标题层级链,比如 [heading1_entry, heading2_entry]
    current_heading_chain = []
    
    for para in doc.paragraphs:
        style_name = para.style.name
        if style_name.startswith('Heading'):
            # 解析标题层级(从样式名中提取,比如"Heading 2"对应层级2)
            heading_level = int(style_name.split()[-1])
            
            # 调整层级链:移除比当前层级高的标题,找到父标题
            while len(current_heading_chain) >= heading_level:
                current_heading_chain.pop()
            
            # 创建当前标题的条目,包含层级、文本、内容和子标题
            heading_entry = {
                'level': heading_level,
                'text': para.text,
                'content': [],
                'children': []
            }
            
            # 将当前标题添加到父节点或根结构
            if current_heading_chain:
                current_heading_chain[-1]['children'].append(heading_entry)
            else:
                doc_structure.append(heading_entry)
            
            # 更新当前层级链
            current_heading_chain.append(heading_entry)
        else:
            # 普通段落:添加到当前最内层标题的内容中
            if current_heading_chain:
                current_heading_chain[-1]['content'].append(para.text)
    
    return doc_structure

# 测试代码:打印文档结构
def print_doc_structure(structure, indent=0):
    for entry in structure:
        # 打印标题
        print(f"{'  '*indent}📌 Level {entry['level']}: {entry['text']}")
        # 打印标题下的内容
        if entry['content']:
            print(f"{'  '*(indent+1)}📝 Content:")
            for content_para in entry['content']:
                print(f"{'  '*(indent+2)}- {content_para}")
        # 递归打印子标题
        if entry['children']:
            print_doc_structure(entry['children'], indent+1)

# 使用示例
if __name__ == "__main__":
    structure = build_document_structure('headerEX.docx')
    print_doc_structure(structure)

关键细节说明

  1. 层级处理逻辑:通过current_heading_chain维护当前的标题路径,遇到新标题时,先弹出链中层级大于等于当前层级的标题,确保找到正确的父节点。比如遇到三级标题时,链中只会保留一级和二级标题。
  2. 结构存储:用嵌套字典保存每个标题的层级、文本、下属内容和子标题,完美还原文档的层级关系。
  3. 样式兼容性:代码默认识别内置的Heading 1-Heading 9样式,如果你的文档用了自定义标题样式,只需要修改startswith('Heading')的判断条件(比如改成style_name == "自定义标题1")即可。

扩展提示

如果你的文档包含表格、图片等非段落内容,可以扩展逻辑:遍历doc.tablesdoc.inline_shapes,通过它们在文档中的位置(比如对比段落的索引)判断属于哪个标题下的内容。

内容的提问来源于stack exchange,提问作者Nisarg Mankad

火山引擎 最新活动