一、业务背景

在很多场景下,我们不希望接收方随意改动 Word 正文,但允许部分区域填写表单、添加批注或者只允许阅读:

  • 对外发送的合同初稿,仅允许填写指定区域;
  • 评审文档,他人只能添加批注,不能直接修改原文;
  • 自动生成的报表,防止下游误改固定模板内容;
  • 批量导出文档时统一加上保护策略,替代手动在 Word 中依次设置。

如果文档量很大,人工逐个打开设置保护、输入密码,效率很低。借助 Python 可以批量加载文档、配置保护规则并另存,适合集成到自动化导出流程里。

说明:本文示例使用 Free Spire.Doc for Python 免费版,它提供了基础文档读写与保护接口,但存在一定页数限制,适合个人或小型项目,使用前可先评估是否适用。


二、环境准备

安装依赖

pip install spire.doc.free

核心能力说明

Word 的限制编辑一般分为几类,也是日常最常用的模式:

  1. 只读保护(AllowOnlyReading):文档整体只读,不能修改;
  2. 仅允许批注(AllowOnlyComments):只能插入批注,正文无法改动;
  3. 仅允许填写表单(AllowOnlyFormFields):只能操作表单域;
  4. 修订模式(AllowOnlyRevisions):所有修改都以修订痕迹留存;
  5. 无保护(NoProtection):解除文档保护。

同时支持设置保护密码;密码仅用于限制编辑,不是文件加密(和另存为加密文档是两个独立能力)。


三、完整示例代码

下面给出几个常用场景的封装示例:设置保护、解除保护、批量处理文档。

from spire.doc import Document, ProtectionType

def set_word_protection(
input_path: str,
output_path: str,
protection_type: ProtectionType,
password: str = ""
):
"""
给 Word 文档添加编辑限制
:param input_path: 源文档路径
:param output_path: 保护后输出路径
:param protection_type: 保护类型
:param password: 保护密码,留空则不设置密码
"""

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")


四、进阶:保留部分区域可编辑

很多需求不是整篇锁定,而是:大部分内容只读,指定段落、片段允许编辑。该库提供 PermissionStart 和 PermissionEnd 权限标记对象,在文档中插入一对同名标记,标记包裹的内容在整篇只读保护下会被豁免,用户可以正常编辑。

原理:这一对标签是 Word 文档权限范围标记,在开启 AllowOnlyReading 保护后,相同 ID 的起止标签之间的内容自动成为可编辑区域。标记可以放在段落子对象集合中,包裹整段或者段落内的局部内容。

示例:将文档第 2 段全部标记为可编辑区域,其余内容只读

from spire.doc import *
from spire.doc.common import *

# 加载文档
doc = Document()
doc.LoadFromFile("Sample.docx")

# 获取第一个节
section = doc.Sections.get_Item(0)

# 创建一对权限标记,使用同一个标识 exception1
start_tag = PermissionStart(doc, "exception1")
end_tag = PermissionEnd(doc, "exception1")

# 获取目标段落(索引从 0 开始,此处取第 2 段)
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()


五、常见注意事项

  1. 密码不是强加密 这类文档保护密码是 Office 的保护锁,安全强度远低于文件打开密码,有成熟工具可以移除;高敏感涉密文档不要只依赖该机制,需要配套权限系统、水印、审计、PDF 转存等方案。

  2. 格式兼容 .doc 和 .docx 的保护行为不完全一致;优先使用 docx。部分老旧版本 WPS / Word 在打开保护文档时,界面提示会有差异。

  3. 服务器环境 Linux 环境缺少中文字体时,文档打开会乱码;需要预装对应字体,或使用容器固化字体环境。

  4. 保护与修订的冲突 如果文档本身开启修订,再叠加保护,部分版本 Office 会改变交互逻辑,建议提前测试。


六、总结

通过几行 Python 代码,我们可以自动化给 Word 设置只读、批注、表单填写等限制编辑策略,把原本重复的人工操作交给脚本。这个方案适合模板导出、批量交付文档、合同自动化流水线。

在落地时要分清两个概念:编辑保护,只是约束修改行为;如果目标是防止泄露、防止复制,还需要结合文件加密、水印、权限管理、转 PDF 等多重手段,不要把文档保护当成安全防线。