Python Word批量去除批注与修订痕迹:清洗定稿
用python-docx通过XML操作批量删除Word文档里的批注、接受所有修订(Track Changes),把审稿稿洗成干净定稿,防止发出的文件暴露修改痕迹。
场景痛点
审稿意见都处理完了,要发终稿给客户,结果文档里还挂着"这里要改""错别字"一堆批注,修订痕迹还开着,对方一打开能看到你删了什么加了什么,尴尬又泄密。手动"接受所有修订-删除所有批注"一份份点,批量处理几十份时用Python一把洗干净。
用到的库
pip install python-docx
完整代码
# -*- coding: utf-8 -*-
"""
清洗 Word 文档:
1) 接受所有修订(Track Changes:保留插入、删除删除标记)
2) 删除所有批注
3) 关闭文档的"修订模式"标记
"""
from pathlib import Path
from docx import Document
from docx.oxml.ns import qn
from lxml import etree
def accept_all_revisions(doc):
"""接受所有修订:保留插入内容,彻底移除删除内容"""
body = doc.element.body
# 1. 处理 w:ins(插入的内容):把它的内容"提出来",去掉 ins 外壳
for ins in body.iter(qn('w:ins')):
parent = ins.getparent()
idx = list(parent).index(ins)
# 把 ins 里的子元素移到原来 ins 的位置
for child in list(ins):
parent.insert(idx, child)
idx += 1
parent.remove(ins)
# 2. 处理 w:del(删除的内容):整个删掉
for d in body.iter(qn('w:del')):
d.getparent().remove(d)
# 3. 处理段落级别的修订标记:w:pPrChange(段落格式修订)、w:rPrChange(run格式修订)
for tag in ('w:pPrChange', 'w:rPrChange', 'w:sectPrChange', 'w:tblPrChange',
'w:trPrChange', 'w:tcPrChange', 'w:cellIns', 'w:cellDel', 'w:cellMerge'):
for el in body.iter(qn(tag)):
el.getparent().remove(el)
# 4. 处理 w:delText(删除的文本节点),删段落里的
for deltext in body.iter(qn('w:delText')):
deltext.getparent().remove(deltext)
def remove_all_comments(doc):
"""删除文档里所有批注"""
# 1. 删除批注引用(正文里的批注锚点)
body = doc.element.body
for comment_ref in body.iter(qn('w:commentRangeStart')):
comment_ref.getparent().remove(comment_ref)
for comment_ref in body.iter(qn('w:commentRangeEnd')):
comment_ref.getparent().remove(comment_ref)
for comment_ref in body.iter(qn('w:commentReference')):
comment_ref.getparent().remove(comment_ref)
# 2. 删除 comments.xml 部件里的实际批注内容(如果存在)
from docx.opc.constants import RELATIONSHIP_TYPE as RT
part = doc.part
for rel in list(part.rels.values()):
if rel.reltype == 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments':
# 清空批注部件
comments_part = rel.target_part
# 清空所有 w:comment 节点
for comment in list(comments_part.element):
comments_part.element.remove(comment)
def turn_off_track_changes(doc):
"""关闭 settings.xml 里的 trackChanges 开关"""
settings = doc.settings.element
for tc in settings.findall(qn('w:trackChanges')):
settings.remove(tc)
def clean_docx(docx_path: Path, output_path: Path):
doc = Document(str(docx_path))
accept_all_revisions(doc)
remove_all_comments(doc)
turn_off_track_changes(doc)
doc.save(str(output_path))
def batch_clean(input_dir, output_dir):
input_dir = Path(input_dir)
output_dir = Path(output_dir)
output_dir.mkdir(parents=True, exist_ok=True)
docx_files = [f for f in input_dir.glob("*.docx") if not f.name.startswith("~$")]
print(f"共 {len(docx_files)} 个文档待清洗")
for docx_file in docx_files:
out = output_dir / docx_file.name
try:
clean_docx(docx_file, out)
print(f"✓ {docx_file.name} -> {out.name}")
except Exception as e:
print(f"✗ {docx_file.name} 失败:{e}")
def demo():
# 演示:造一个带修订和批注的文档
doc = Document()
doc.add_paragraph("这是初稿内容。")
p = doc.add_paragraph("下面这句将被删除。")
p2 = doc.add_paragraph("这是要插入的新句子。")
out = Path("./draft_with_revisions.docx")
doc.save(str(out))
print(f"演示文件已生成:{out}")
print("(真实的修订/批注标记需要在Word里打开并开启修订模式修改后才有,本脚本直接处理XML)")
if __name__ == "__main__":
batch_clean(
input_dir="./word_docs",
output_dir="./final_clean",
)
代码讲解
Word的修订(Track Changes)在XML里是用 w:ins 表示插入、w:del 表示删除、w:delText 表示被删掉的文字。"接受所有修订"在XML层面就是:把 w:ins 外壳剥掉,让里面的内容变成普通正文;把 w:del 和 w:delText 整个删掉,因为这些是被否决的改动。
批注是另外一套机制:正文里有 w:commentRangeStart/End 和 w:commentReference 三个锚点,实际批注内容存在单独的 comments.xml 部件里。删批注要同时清掉这两边:正文锚点 + 批注部件里的 comment 节点。
最后 turn_off_track_changes() 把 settings.xml 里的 w:trackChanges 开关删掉,这样用户打开新文档后不会再自动进入修订模式。
运行结果
final_clean 目录里是清洗后的文档。打开后:所有批注气泡消失,所有修订痕迹变成普通文字(插入的内容保留、删除的内容消失),状态栏不再显示"修订: 打开"。可以安全发出去。
注意事项
- 这是XML级别的粗暴处理,对绝大多数"正常修订"有效。如果文档里有复杂的移动修订、表格修订、批注嵌套,可能漏网,处理完务必抽查一份。
- 本脚本是"接受所有修订",不是"拒绝所有修订"。如果要拒绝,逻辑反过来:保留
w:del内容、删掉w:ins内容。 - 删批注前确认所有批注意见都已经处理完,删了就找不回来了。
- 处理完建议用Word打开看一眼"审阅-修订"面板,确认没有残留修订标记。
- 加密文档、带宏的docm文件可能报错,会在控制台跳过。

更新时间:2026-09-14 21:44:35