拓冰建站拓冰建站
首页 / 资讯中心 / 正文

用Python解除Excel工作表保护:先分清加密与权限,再选对工具

如果你正在处理一批带工作表保护的 Excel 模板可能会遇到一个很常见的尴尬文件能打开但公式列被锁死想批量取消保护又不想一个个去点“审阅 → 取消工作表保护”。这个时候很多人会想到用 Python 来处理 Excel 文件添加保护与解除保护。想法没错但如果你直接搜代码去改sheet.protection大概率会在真实文件上翻车。我最初处理类似任务时以为“Excel 保护”只有一种。后来才发现一个文件里可能同时存在文件打开密码、工作簿结构保护、工作表保护三种机制而它们背后是完全不同的数据结构。甚至可以说Excel 里的“保护”并不总代表“加密”很多保护只是在 XML 里写了一个标志位。只有先把这张地图看清楚之后的代码才不会变成一排随时会踩爆的雷。1. 先分清你处理的是哪一种“保护”1.1 三种 Excel 保护入口和效果完全不同很多人把“Excel 加了保护”当成一个统一概念实际上至少有三类。保护类型你能看到的现象文件本身是否被加密Python 处理难度文件打开密码双击文件就弹密码框不输密码看不到内容是文件头不是标准 zip必须先用正确密码解密或走 Office 客户端流程工作表保护文件能正常打开但部分单元格不能编辑点“取消工作表保护”需要密码否工作簿 XML 里通常只是保存了保护标志和弱哈希很容易openpyxl 可以直接读写相关属性工作簿结构保护打开后无法插入、删除、移动、重命名工作表相关菜单是灰的否同样是 XML 里的保护标签可以通过 openpyxl 或 COM 处理之所以要区分它们是因为处理方式完全不同。比如openpyxl打开文件时报“File is not a zip file”通常不是代码写错了而是文件根本是加密过的。只有文件本身被 Office 加密后它才不是一个普通 zip 容器openpyxl 无法直接处理这种数据流。而如果只是普通的工作表保护哪怕原密码丢失Python 都不需要和你填的密码“核对成功”因为它读的是底层 XML。只要你把sheet.protection里的状态改掉再保存出来Excel 客户端就会认为这个工作表没有被保护。1.2 openpyxl、COM、解密库按目标选工具看清类型之后工具选型就很自然。openpyxl纯 Python不依赖 Windows 和 Excel 安装适合处理.xlsx和.xlsm工作簿里的单元格样式、公式、工作表保护属性。它不能打开真正带打开密码的加密文件也不能处理旧版.xls。pywin32 / COM必须在安装 Excel 的 Windows 机器上运行。它相当于用 Python 驱动 Excel 客户端能执行“保护工作簿结构”“保护工作表”“取消保护”这类菜单操作也能处理.xls。msoffcrypto-tool专门处理 Office 文件加密。它不能用暴力方式猜密码但如果你自己记得密码或者拿到了授权密码它能先把带打开密码的文件解成普通 xlsx再交给 openpyxl 处理。我不建议在一个脚本里硬塞“万能方案”。更稳妥的做法是先识别文件属于哪一层再走对应分支。这也是后面所有代码设计的底层逻辑。1.3 单文件跑通不等于批量任务可行有一个经验很重要单文件跑通只能证明“流程没有断”证明不了“代码能处理你的全部文件”。Excel 文件之间的差异比想象中大得多。同一批文件可能是不同人创建的有人加了工作表保护有人没加有人用的是.xlsm宏文件有人存成了旧版.xls有人甚至给文件设置了打开密码但忘了告诉你。只要这些情况有一个没处理批量任务就会在跑到一半时中断。所以真正有用的流程应该是先拿一个样例文件跑通再拿三个不同来源的样例文件做验证最后再铺到整个目录。后文提到的几个步骤也都是围绕这个思路展开的。2. 用 openpyxl 给工作表添加保护先跑通最小案例2.1 环境准备与最小操作示例使用 openpyxl 不需要安装 Office预处理最轻量。建议先建虚拟环境再安装依赖。python -m venv .venv # Windows PowerShell .\.venv\Scripts\Activate.ps1 # macOS / Linux source .venv/bin/activate python -m pip install openpyxl然后写一个最小示例打开文件并开启工作表保护。from openpyxl import load_workbook wb load_workbook(月度模板.xlsx) ws wb[Sheet1] ws.protection.sheet True ws.protection.password change-me wb.save(月度模板_受保护.xlsx)这段代码完成了“给工作表加保护”的最小闭环。之后用 Excel 打开新文件Sheet1 的编辑操作会被限制。这里要注意openpyxl 对密码的处理只是帮你往 XML 里写入一个 Excel 能识别的哈希值它的作用是让 Excel 弹出密码框验证而不是给文件内容加密。所以这里不要把它当作安全防护来用它适合的是“防止别人手滑修改公式”这类协作场景。2.2 先把需要手工编辑的单元格“解锁”如果只是在ws.protection.sheet True后保存文件你会发现整个工作表都被锁住包括填写数据的区域。实际业务里通常不是这样你可能只想锁住公式列但允许用户填写“考核分数”“备注”等录入列。这就要理解单元格的locked属性与工作表保护的关系。Excel 里每个单元格默认都带一个locked属性但这个属性在未开启工作表保护的时候不会生效。只有当你开启了工作表保护Excel 才会检查单元格是锁定还是解锁。如果你只是保护工作表却没有把数据录入区标成“不锁定”那么输入列也会一起锁死。正确的做法是先把你希望用户编辑的单元格设为lockedFalse再开启工作表保护。from openpyxl import load_workbook wb load_workbook(月度模板.xlsx) ws wb[Sheet1] # 允许用户编辑第 2 到第 100 行的 A 到 D 列 for row in ws.iter_rows(min_row2, max_row100, min_col1, max_col4): for cell in row: cell.protection.locked False # 开启工作表保护 ws.protection.sheet True ws.protection.password change-me wb.save(月度模板_受保护.xlsx)如果后续需要增加一个可编辑区域不需要重做整张表只要再遍历一次对应列把cell.protection.locked设置为False再重新保存即可。2.3 解除工作表保护的常用写法解除保护比很多人想的更直接。openpyxl 不需要像 Excel 客户端那样验证密码因为保护信息只是工作簿 XML 里的一个状态。只要你自己维护这份文件或者已经取得授权就可以把相应标志位清掉。from openpyxl import load_workbook wb load_workbook(月度模板_受保护.xlsx) ws wb[Sheet1] ws.protection.sheet False ws.protection.password None wb.save(月度模板_已解除.xlsx)如果目标工作簿里有多个工作表都开了保护可以循环处理。wb load_workbook(多表受保护.xlsx) for ws in wb.worksheets: ws.protection.sheet False ws.protection.password None wb.save(多表已解除.xlsx)工作表保护并不是文件加密它是 Excel 客户端里的“操作约束”。对于自己创建的模板忘记密码后用 openpyxl 重置状态属于正常的本地维护如果是别人明确不想让你改动的文件先取得授权再处理。3. 解除保护前先判断文件是真的“加密”还是只是“设了权限”3.1 工作表保护不等于文件加密很多教程会混淆两件事一个是“工作表被锁定”另一个是“文件打开要密码”。前者通常只是劳动分工约束后者才是真正的文件访问控制。在 Python 里判断也非常简单。如果一个文件只是工作表被保护openpyxl 能正常加载因为整个.xlsx文件本质上是一个 zip 包里面的单元格数据是明文 XML。而如果一个文件设置了打开密码它往往不再是一个标准的 zip 包你需要先解密才能继续操作。所以遇到操作报错不要急着查 openpyxl 参数先确认报错是不是发生在文件读取阶段。常见情况是用 openpyxl 打开时报File is not a zip file用zipfile模块检查时返回False或者文件扩展名是.xlsx但实际文件头看起来不是PK。这种文件大概率是带打开密码的加密 Office 文件。对它来说你已经不是“解除工作表保护”的问题而是要先解密文件拿到明文的 xlsx 之后再继续做后续处理。3.2 遇到打开密码保护先用正确密码解出明文处理带打开密码的.xlsx我常用的是msoffcrypto-tool。注意它不是用来暴力猜密码的而是在你明确知道密码的前提下把加密文件解成可以进一步处理的普通 xlsx。先安装依赖pip install msoffcrypto-tool然后写一段解密逻辑import msoffcrypto with open(加密模板.xlsx, rb) as f: office_file msoffcrypto.OfficeFile(f) if office_file.is_encrypted(): office_file.load_key(password你的正确密码) with open(解密模板.xlsx, wb) as out: office_file.decrypt(out)这段代码跑完后解密模板.xlsx就是一个没有打开密码的普通 xlsx 文件。之後你可以继续用 openpyxl 读取、修改、添加或移除工作表保护。如果你真的把打开密码忘了事情会麻烦很多这不是靠几行 Python 就能轻松绕过的。真正实用的方案是找历史备份或者从 OA 系统、共享盘里找回旧版本。不要指望用某个脚本“秒破”文件打开密码那不是教程能替你解决的问题。3.3 动手之前做一份不改扩展名的备份无论是给工作表加保护还是解除保护任何一次wb.save()都会重写整个文件。这听起来很简单实际操作时却有不少意外。比如某个模板里包含着宏、数据透视表缓存、特殊格式或外部链接openpyxl 重写保存后有可能会丢掉部分 Excel 不常暴露的结构。对于普通数据表来说问题不大但在量产环境里我从来不敢直接覆盖原始文件。更安全的做法是先复制一份原文件再对副本操作。cp 原始模板.xlsx 原始模板_backup.xlsx如果是在脚本里遍历目录也建议把输出结果统一放到另一个output/目录而不是原地覆盖。这样一旦发现问题你只需要重新跑一次不需要从版本管理或回收站里恢复。4. 需要更接近 Excel 客户端的行为时用 COM 补齐4.1 为什么还需要 Windows Excel 这条路openpyxl 处理绝大多数保护场景已经够用但它毕竟不是真正的 Excel。有两个场景我认为必须考虑 COM。第一个是处理“工作簿结构保护”。虽然 openpyxl 也能操作工作簿保护对象但很多公司内部生成的文件结构复杂有的还带着旧版.xls格式或宏权限直接让 openpyxl 去解容易在保存后出现格式差异。第二个场景是UserInterfaceOnly这种只能在 Excel 客户端里生效的设置。比如你想保护工作表但希望后续脚本或宏仍然能改单元格数据这时用 openpyxl 很难完美模拟 Excel 的 UI 行为而 COM 可以直接调用 Excel 的Worksheet.Protect方法。换句话说openpyxl 适合“不需要打开 Excel 的批处理”场景COM 适合“你就是要模拟一个用户用 Excel 界面做完所有操作”的场景。4.2 COM 示例保护工作簿结构和工作表使用 COM 需要本机安装 Windows 版 Excel并且 Python 环境里有pywin32pip install pywin32下面这段代码会打开 Excel对工作簿启用“保护工作簿结构”再对指定工作表开启保护最后保存并退出。import win32com.client as win32 excel win32.DispatchEx(Excel.Application) try: excel.Visible False excel.DisplayAlerts False wb excel.Workbooks.Open(rC:\data\月度模板.xlsx) # 保护工作簿结构禁止插入、删除、移动、重命名工作表 wb.Protect(Passwordyour-password, StructureTrue, WindowsFalse) # 保护指定工作表 ws wb.Worksheets(Sheet1) ws.Protect(Passwordyour-password, ContentsTrue) wb.Save() wb.Close(False) finally: excel.Quit()解除保护的方法名称和我们手工点的菜单一致# 解除工作簿结构保护 wb.Unprotect(Passwordyour-password) # 解除工作表保护 ws.Unprotect(Passwordyour-password)如果你在一个文件上需要同时交替使用多个逻辑不要在一个try块里把 Protect 和 Unprotect 堆在一起那样出错后很难判断到底是哪一步没执行成功。更好的做法是把保护逻辑封装成独立函数每个函数只做一件事。4.3 COM 处理时的几个执行纪律COM 脚本最大的问题不是语法而是进程状态。Excel 是一个重量级 GUI 应用如果finally里没有退出哪怕脚本报错了后台也可能残留一个不可见的 Excel 进程。所以我的纪律是使用DispatchEx(Excel.Application)创建独立实例使用后主动Quit()。在finally块里做清理不要只在正常路径下退出。打开文件时尽量使用绝对路径避免脚本
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门