在日常办公中,处理Word文档的修订(Track Changes)是合同审核、团队协作、版本管理中的高频需求。如果每次都需要人工逐一开启修订、检查变更、接受或拒绝,效率极低。借助Python的Spire.Doc库,我们可以将这一系列操作完全自动化,从而高效处理大批量文档。本文将从环境搭建出发,逐步演示如何使用Python实现Word修订的完整自动化流程。
## 环境准备
首先通过pip安装Spire.Doc库(注意不是python-docx,它不支持修订操作的高级API):该库运行时不依赖本机安装Microsoft Word,适合服务器或无GUI环境。
## 1. 开启修订功能
在文档发送给外部人员审阅前,通常希望默认开启修订。只需将Document对象的TrackChanges属性设置为True:- from spire.doc import *
- doc = Document()
- doc.LoadFromFile("示例.docx")
- doc.TrackChanges = True
- doc.SaveToFile("开启修订.docx", FileFormat.Docx2016)
- doc.Close()
复制代码 保存后,用Word打开该文件,“审阅”选项卡下的“修订”功能将处于启用状态。注意:这个设置只影响后续的手动编辑,不会追溯标记已有内容。
## 2. 关闭修订功能
关闭修订同样简单,将TrackChanges设为False即可:- from spire.doc import *
- doc = Document()
- doc.LoadFromFile("开启修订.docx")
- doc.TrackChanges = False
- doc.SaveToFile("关闭修订.docx", FileFormat.Docx2016)
- doc.Close()
复制代码 关闭后,后续编辑不会产生修订记录,但文档中已有的修订仍然保留,需要单独接受或拒绝。
## 3. 以编程方式添加修订(模拟审阅者)
有时我们希望脚本像审阅者一样提出修改建议,而非直接修改最终内容。可以先调用Document.StartTrackRevisions(),编辑后再调用StopTrackRevisions():- from spire.doc import *
- document = Document()
- document.LoadFromFile("示例.docx")
- # 开始记录修订,指定作者和时间为当前
- document.StartTrackRevisions("Python用户", DateTime())
- # 在第四个段落末尾追加文本
- document.Sections[0].Paragraphs[3].AppendText("Python用户添加了新文本!")
- # 删除第五个段落
- document.Sections[0].Paragraphs.RemoveAt(4)
- # 停止记录修订
- document.StopTrackRevisions()
- document.SaveToFile("添加修订.docx", FileFormat.Docx2016)
- document.Close()
复制代码 执行后,添加和删除的内容都会以修订形式呈现,而不是直接生效。
## 4. 检查文档是否存在未处理修订
在决定接受或拒绝之前,最好先判断文档是否包含修订。Document.HasChanges属性可快速检测:- from spire.doc import *
- doc = Document()
- doc.LoadFromFile("审阅.docx")
- if doc.HasChanges:
- print("文档包含待处理修订!")
- else:
- print("无待处理修订!")
- doc.Close()
复制代码
## 5. 接受或拒绝所有修订
审阅完成后,通常需要批量处理整个文档。Spire.Doc提供了直接的方法:
接受所有修订:- from spire.doc import *
- doc = Document()
- doc.LoadFromFile("审阅.docx")
- if doc.HasChanges:
- doc.AcceptChanges()
- print("已接受所有修订!")
- doc.SaveToFile("接受修订.docx", FileFormat.Docx2016)
- doc.Close()
复制代码 拒绝所有修订:- from spire.doc import *
- doc = Document()
- doc.LoadFromFile("审阅.docx")
- if doc.HasChanges:
- doc.RejectChanges()
- print("已拒绝所有修订!")
- doc.SaveToFile("拒绝修订.docx", FileFormat.Docx2016)
- doc.Close()
复制代码
## 6. 提取修订信息(包括格式变更)
如果需要详细了解修改变更,可以使用Document.GetRevisionInfos()获取插入、删除和格式修改三类信息。下面示例分别提取并输出:- from spire.doc import *
- doc = Document()
- doc.LoadFromFile("添加修订.docx")
- # 辅助函数:转换格式属性
- from spire.doc.common import *
- def value_to_string(value):
- if value is None:
- return ""
- if hasattr(value, "ToString"):
- return value.ToString()
- return str(value)
- def bool_to_chinese(value):
- return "是" if value else "否"
- def get_character_style(text_range):
- cf = text_range.CharacterFormat
- return {
- "isBold": cf.Bold,
- "TextColor": value_to_string(cf.TextColor),
- "HighlightColor": value_to_string(cf.HighlightColor),
- "FontName": str(cf.FontName),
- "UnderlineStyle": str(cf.UnderlineStyle)
- }
- def style_to_string(style):
- return (
- "是否加粗:" + bool_to_chinese(style["isBold"]) + ";"
- "字体颜色:" + style["TextColor"] + ";"
- "高亮颜色:" + style["HighlightColor"] + ";"
- "字体名称:" + style["FontName"] + ";"
- "下划线样式:" + style["UnderlineStyle"]
- )
- # 获取修订信息集合
- revision_info_collection = doc.GetRevisionInfos()
- insert_revisions = []
- delete_revisions = []
- format_revisions = []
- for index in range(revision_info_collection.Count):
- rev = revision_info_collection.get_Item(index)
- author = rev.Author
- obj = rev.OwnerObject
- if rev.RevisionType == RevisionType.Insertion:
- if isinstance(obj, TextRange):
- insert_revisions.append({"author": author, "text": obj.Text})
- elif rev.RevisionType == RevisionType.Deletion:
- if isinstance(obj, TextRange):
- delete_revisions.append({"author": author, "text": obj.Text})
- elif rev.RevisionType == RevisionType.FormatChange:
- if isinstance(obj, TextRange):
- # 获取原始格式和最终格式
- doc.RevisionsView = RevisionsView.Original
- original_style = get_character_style(obj)
- doc.RevisionsView = RevisionsView.Final
- final_style = get_character_style(obj)
- format_revisions.append({"author": author, "text": obj.Text,
- "original_style": original_style,
- "final_style": final_style})
- doc.Close()
- print(f"插入修订数量:{len(insert_revisions)}")
- for r in insert_revisions:
- print(f" 作者:{r['author']},插入内容:{repr(r['text'])}")
- print(f"\n删除修订数量:{len(delete_revisions)}")
- for r in delete_revisions:
- print(f" 作者:{r['author']},删除内容:{repr(r['text'])}")
- print(f"\n格式修订数量:{len(format_revisions)}")
- for r in format_revisions:
- print(f" 作者:{r['author']},修订文本:{repr(r['text'])}")
- print(" 原始格式:" + style_to_string(r["original_style"]))
- print(" 最终格式:" + style_to_string(r["final_style"]))
复制代码 这个能力可用于生成审阅报告或进行自动化审批前的风险检查。
## 7. 按作者选择性接受/拒绝修订
不同作者可能对应不同的审批策略。AcceptChanges()和RejectChanges()作用于整个文档,若需精细控制,可遍历修订集合,针对指定作者调用Accept()或Reject()。注意使用倒序遍历,避免索引错位:- from spire.doc import *
- doc = Document()
- doc.LoadFromFile("添加修订.docx")
- target_author = "Python用户"
- action = "accept" # 或 "reject"
- revision_info_collection = doc.GetRevisionInfos()
- for i in range(revision_info_collection.Count - 1, -1, -1):
- rev = revision_info_collection.get_Item(i)
- if rev.Author == target_author:
- if action == "accept":
- rev.Accept()
- elif action == "reject":
- rev.Reject()
- else:
- raise ValueError("操作类型必须是 'accept' 或 'reject'")
- output_file = "按作者接受修订.docx" if action == "accept" else "按作者拒绝修订.docx"
- doc.SaveToFile(output_file, FileFormat.Docx2016)
- doc.Close()
复制代码
## 8. 通过比较两个文档生成修订记录
当协作者返回的文档未开启修订时,可以使用Document.Compare()方法对比原始版本和修改版,差异会自动转换为修订:- from spire.doc import *
- original = Document()
- original.LoadFromFile("合同_v1.docx")
- revised = Document()
- revised.LoadFromFile("合同_v2.docx")
- original.Compare(revised, "审阅用户")
- original.SaveToFile("合同比较结果.docx", FileFormat.Docx2016)
- original.Close()
- revised.Close()
复制代码 生成的文档可直接在Word中查看差异,并继续接受或拒绝。
## 总结
通过Python与Spire.Doc库结合,我们可以轻松实现对Word修订的自动化控制:开启/关闭修订、模拟审阅者添加修订、批量接受/拒绝、提取详细修订信息、按作者筛选处理,以及文档比较生成修订。这些方法特别适合合同审批、制度文件管理、报告协作等场景,能显著减少人工操作,构建高效文档处理流水线。 |