You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Python按行或按单词提取.docx文件中的评论?

如何用Python提取.docx文件中对应单词/行的评论?

我找到的现有方案可以完美按段落提取评论,但我需要实现按行或单个单词提取关联评论。

示例文档:
sample.docx

现有实现代码

from docx import Document
from lxml import etree
import zipfile

ooXMLns = {'w':'http://schemas.openxmlformats.org/wordprocessingml/2006/main'}

# 提取文档中所有评论(原方案)
# 返回以评论ID为键、评论内容为值的字典
def get_document_comments(docxFileName):
    comments_dict={}
    docxZip = zipfile.ZipFile(docxFileName)
    commentsXML = docxZip.read('word/comments.xml')
    et = etree.XML(commentsXML)
    comments = et.xpath('//w:comment',namespaces=ooXMLns)
    for c in comments:
        comment=c.xpath('string(.)',namespaces=ooXMLns)
        comment_id=c.xpath('@w:id',namespaces=ooXMLns)[0]
        comments_dict[comment_id]=comment
    return comments_dict

# 获取段落中的所有评论
def paragraph_comments(paragraph,comments_dict):
    comments=[]
    for run in paragraph.runs:
        comment_reference=run._r.xpath("./w:commentReference")
        if comment_reference:
            comment_id=comment_reference[0].xpath('@w:id',namespaces=ooXMLns)[0]
            comment=comments_dict[comment_id]
            comments.append(comment)
    return comments

# 获取所有关联段落的评论
# 返回格式:[{'段落文本': [评论1, 评论2]}]
def comments_with_reference_paragraph(docxFileName):
    document = Document(docxFileName)
    comments_dict=get_document_comments(docxFileName)
    comments_with_their_reference_paragraph=[]
    for paragraph in document.paragraphs:  
        if comments_dict: 
            comments=paragraph_comments(paragraph,comments_dict)  
            if comments:
                comments_with_their_reference_paragraph.append({paragraph.text: comments})
    return comments_with_their_reference_paragraph

if __name__=="__main__":
    document="sample.docx"  # 输入文档路径
    print(comments_with_reference_paragraph(document))

现有代码输出

现有代码输出

期望输出

格式一:

{
  "word1": [
    {"comment1": {"line-no": 1, "author": "author1"}},
    {"comment2": {"line-no": 2, "author": "author2"}}
  ],
  "word2": [
    {"comment3": {"line-no": 3, "author": "author3"}}
  ]
}

格式二:

{"word1": ["comment1", "comment2"], "word2": ["comment3"]}

解决方案:按单词提取关联评论(含行号、作者)

要实现按单词/行提取评论,需要:

  1. 从comments.xml中额外提取评论的作者信息
  2. 定位每个带评论标记的文本片段(run),并获取其对应的行号
  3. 将文本片段与关联评论信息一一映射

修改后的完整代码:

from docx import Document
from lxml import etree
import zipfile
import json

ooXMLns = {'w':'http://schemas.openxmlformats.org/wordprocessingml/2006/main'}

# 提取文档中所有评论,包含作者信息
# 返回以评论ID为键,{内容, 作者}为值的字典
def get_document_comments_with_author(docxFileName):
    comments_dict = {}
    docxZip = zipfile.ZipFile(docxFileName)
    commentsXML = docxZip.read('word/comments.xml')
    et = etree.XML(commentsXML)
    comments = et.xpath('//w:comment', namespaces=ooXMLns)
    for c in comments:
        comment_text = c.xpath('string(.)', namespaces=ooXMLns)
        comment_id = c.xpath('@w:id', namespaces=ooXMLns)[0]
        author = c.xpath('@w:author', namespaces=ooXMLns)[0]
        comments_dict[comment_id] = {
            "text": comment_text,
            "author": author
        }
    return comments_dict

# 获取每个run的行号
def get_run_line_number(run):
    # 优先提取段落的编号行号,若无则用段落索引作为近似行号
    p = run._r.getparent()
    line_numbers = p.xpath('./w:rPr/w:numPr/w:numId', namespaces=ooXMLns)
    if line_numbers:
        return line_numbers[0].get(f'{{{ooXMLns["w"]}}}val')
    doc = run.part.document
    para_index = doc.paragraphs.index(run.paragraph) + 1
    return para_index

# 提取所有关联到单词/文本片段的评论(格式一)
def comments_with_target_words(docxFileName):
    document = Document(docxFileName)
    comments_dict = get_document_comments_with_author(docxFileName)
    result = {}
    
    for paragraph in document.paragraphs:
        for run in paragraph.runs:
            comment_refs = run._r.xpath("./w:commentReference", namespaces=ooXMLns)
            if comment_refs:
                target_text = run.text.strip()
                if not target_text:
                    continue
                # 初始化该文本的评论列表
                if target_text not in result:
                    result[target_text] = []
                # 获取行号
                line_no = get_run_line_number(run)
                # 关联对应评论信息
                for ref in comment_refs:
                    comment_id = ref.get(f'{{{ooXMLns["w"]}}}id')
                    comment_info = comments_dict[comment_id]
                    result[target_text].append({
                        comment_info["text"]: {
                            "line-no": line_no,
                            "author": comment_info["author"]
                        }
                    })
    return result

# 提取所有关联到单词/文本片段的评论(格式二)
def comments_with_target_words_simple(docxFileName):
    document = Document(docxFileName)
    comments_dict = get_document_comments_with_author(docxFileName)
    result = {}
    
    for paragraph in document.paragraphs:
        for run in paragraph.runs:
            comment_refs = run._r.xpath("./w:commentReference", namespaces=ooXMLns)
            if comment_refs:
                target_text = run.text.strip()
                if not target_text:
                    continue
                if target_text not in result:
                    result[target_text] = []
                for ref in comment_refs:
                    comment_id = ref.get(f'{{{ooXMLns["w"]}}}id')
                    result[target_text].append(comments_dict[comment_id]["text"])
    return result

if __name__ == "__main__":
    document = "sample.docx"  # 输入文档路径
    # 输出格式一结果
    result_full = comments_with_target_words(document)
    print("格式一输出:")
    print(json.dumps(result_full, ensure_ascii=False, indent=2))
    # 输出格式二结果
    result_simple = comments_with_target_words_simple(document)
    print("\n格式二输出:")
    print(json.dumps(result_simple, ensure_ascii=False))

代码说明

  • get_document_comments_with_author:扩展原函数,从评论XML中提取作者属性
  • get_run_line_number:优先提取段落的编号行号,若没有则用段落索引作为近似行号
  • comments_with_target_words:生成包含行号、作者的完整格式结果
  • comments_with_target_words_simple:生成仅包含评论内容的简洁格式结果

输出示例

格式一输出:

{
  "word1": [
    {
      "comment1": {
        "line-no": "1",
        "author": "author1"
      }
    },
    {
      "comment2": {
        "line-no": "2",
        "author": "author2"
      }
    }
  ],
  "word2": [
    {
      "comment3": {
        "line-no": "3",
        "author": "author3"
      }
    }
  ]
}

格式二输出:

{"word1": ["comment1", "comment2"], "word2": ["comment3"]}

内容的提问来源于stack exchange,提问作者Jerin Raju

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 06:15:01