在合同初稿、评审文档、自动生成报表和批量导出模板等场景中,常见需求是锁住Word正文,只允许批注、填写表单或编辑指定区域。人工逐个打开文档设置保护并输入密码效率很低,适合用Python把加载、保护配置和另存动作串成批处理脚本。本文示例基于Free Spire.Doc for Python免费版,它提供基础文档读写与保护接口,但有一定页数限制,落地前需评估项目规模。
一、依赖与保护模式
安装依赖:pip install spire.doc.free。核心枚举ProtectionType包含常用模式:AllowOnlyReading表示整篇只读;AllowOnlyComments表示只能插入批注;AllowOnlyFormFields表示只能操作表单域;AllowOnlyRevisions表示修改以修订痕迹留存;NoProtection表示解除保护。设置保护时可同时传入密码,但该密码仅用于限制编辑,不是文件打开密码,也不等同于另存为加密文档。
二、基础封装:设置与解除保护
下面的脚本把加载文档、调用Protect或Unprotect、保存输出封装成函数。set_word_protection的四个参数分别是源文档路径、输出路径、保护类型和保护密码;密码留空则不设置密码。remove_word_protection用于解除保护,如果原文档设置过密码,需要传入正确密码,否则解除动作无法完成。
- from spire.doc import Document, ProtectionType
- def set_word_protection(input_path: str, output_path: str, protection_type: ProtectionType, password: str = ""):
- # 给Word文档添加编辑限制
- doc = Document()
- doc.LoadFromFile(input_path)
- doc.Protect(protection_type, password)
- doc.SaveToFile(output_path)
- doc.Close()
- def remove_word_protection(input_path: str, output_path: str, password: str = ""):
- # 解除编辑保护,若设置过密码则需传入正确密码
- doc = Document()
- doc.LoadFromFile(input_path)
- doc.Unprotect(password)
- doc.SaveToFile(output_path)
- doc.Close()
- if __name__ == "__main__":
- # 场景1:仅允许批注,并设置保护密码
- set_word_protection(
- input_path="template.docx",
- output_path="protected_comments.docx",
- protection_type=ProtectionType.AllowOnlyComments,
- password="Demo@2026"
- )
- # 场景2:只读,不设置密码
- set_word_protection(
- input_path="template.docx",
- output_path="protected_readonly.docx",
- protection_type=ProtectionType.AllowOnlyReading
- )
- # 场景3:解除保护(按需取消注释)
- # remove_word_protection("protected_comments.docx", "unprotected.docx", password="Demo@2026")
复制代码
调用时可根据业务选择保护类型:对外合同初稿可用AllowOnlyFormFields限定表单填写,评审文档可用AllowOnlyComments避免正文被直接改动,固定模板报表可用AllowOnlyReading防止下游误改。批量导出流程中,把上述函数放在文档生成之后、交付之前执行即可。
三、进阶:保留部分区域可编辑
很多需求不是整篇锁定,而是大部分内容只读、指定段落或片段允许编辑。该库提供PermissionStart和PermissionEnd权限标记对象,在文档中插入一对同名标记,标记包裹的内容在整篇只读保护下会被豁免,用户可以正常编辑。原理是这对标签作为Word文档权限范围标记,在开启AllowOnlyReading保护后,相同ID的起止标签之间自动成为可编辑区域;标记可放在段落子对象集合中,包裹整段或段落内局部内容。
示例将文档第2段全部标记为可编辑区域,其余内容只读。注意段落索引从0开始,get_Item(1)取第2段;start_tag和end_tag使用同一个标识exception1,并通过ChildObjects.Insert(0, start_tag)和ChildObjects.Add(end_tag)插入段落首尾。
- from spire.doc import *
- from spire.doc.common import *
- doc = Document()
- doc.LoadFromFile("Sample.docx")
- section = doc.Sections.get_Item(0)
- start_tag = PermissionStart(doc, "exception1")
- end_tag = PermissionEnd(doc, "exception1")
- # 取第2段,索引从0开始
- target_paragraph = section.Paragraphs.get_Item(1)
- target_paragraph.ChildObjects.Insert(0, start_tag)
- target_paragraph.ChildObjects.Add(end_tag)
- doc.Protect(ProtectionType.AllowOnlyReading, "password")
- doc.SaveToFile("output/RestrictionException.docx")
- doc.Close()
复制代码
这种模式适合模板中大部分说明文字只读、少量填写区需要放开的场景。标记ID要成对且同名,位置要落在目标段落的子对象集合中;如果只插入一端标记,权限范围不会按预期生效。
四、常见注意事项
保护密码不是强加密。这类文档保护密码属于Office保护锁,安全强度低于文件打开密码,且有成熟工具可以移除;高敏感涉密文档不要只依赖该机制,需要配套权限系统、水印、审计和PDF转存等方案。
格式兼容方面,.doc和.docx的保护行为不完全一致,优先使用docx;部分老旧版本WPS或Word在打开保护文档时,界面提示会有差异。服务器环境若缺少中文字体,Linux下文档打开可能乱码,需要预装对应字体或用容器固化字体环境。若文档本身开启修订,再叠加保护,部分版本Office会改变交互逻辑,建议提前测试。免费版存在页数限制,批量处理前应先用样本验证。
五、总结
通过Python脚本可以批量给Word设置只读、批注、表单填写等限制编辑策略,把重复的人工设置交给自动化导出流程。落地时要区分编辑保护与文件加密:编辑保护只约束修改行为;如果目标是防止泄露、防止复制,还需要结合文件加密、水印、权限管理和转PDF等多重手段。 |