下载 链接:https://pan.baidu.com/s/12ysKCxmt59WTKIuW0Hl2hw?pwd=123h

import os
import tkinter as tk
from tkinter import filedialog, messagebox, scrolledtext
import win32com.client
classWordUnprotectorGUI:
def__init__(self, root):
self.root = root
self.root.title("公众号-办公经验说分享:Word 文档批量解除只读保护")
self.root.geometry("650x450")
self.source_folder = tk.StringVar()
self.target_folder = tk.StringVar()
self.password = tk.StringVar()
self.create_widgets()
defcreate_widgets(self):
# 源文件夹
tk.Label(self.root, text="源文件夹(受保护的文档):").grid(row=0, column=0, sticky='e', padx=5, pady=5)
tk.Entry(self.root, textvariable=self.source_folder, width=50).grid(row=0, column=1, padx=5, pady=5)
tk.Button(self.root, text="浏览...", command=self.browse_source).grid(row=0, column=2, padx=5)
# 目标文件夹
tk.Label(self.root, text="目标文件夹(输出位置):").grid(row=1, column=0, sticky='e', padx=5, pady=5)
tk.Entry(self.root, textvariable=self.target_folder, width=50).grid(row=1, column=1, padx=5, pady=5)
tk.Button(self.root, text="浏览...", command=self.browse_target).grid(row=1, column=2, padx=5)
tk.Label(self.root, text="(若与源文件夹相同,将直接覆盖原文件)", fg="gray", font=("Arial", 9)).grid(row=2, column=1, sticky='w', padx=5)
# 密码输入
tk.Label(self.root, text="保护密码(必填):").grid(row=3, column=0, sticky='e', padx=5, pady=5)
tk.Entry(self.root, textvariable=self.password, width=30, show="*").grid(row=3, column=1, sticky='w', padx=5, pady=5)
tk.Label(self.root, text="(输入当初设置的保护密码)", fg="gray", font=("Arial", 9)).grid(row=3, column=1, sticky='e', padx=5)
# 处理按钮
self.process_btn = tk.Button(self.root, text="开始解除保护", command=self.process, bg='lightcoral', font=('Arial', 12))
self.process_btn.grid(row=4, column=1, pady=15)
# 日志
tk.Label(self.root, text="处理日志:").grid(row=5, column=0, sticky='ne', padx=5)
self.log_text = scrolledtext.ScrolledText(self.root, height=15, width=80)
self.log_text.grid(row=6, column=0, columnspan=3, padx=10, pady=5, sticky='nsew')
self.log_text.config(state='disabled')
self.root.grid_rowconfigure(6, weight=1)
self.root.grid_columnconfigure(1, weight=1)
defbrowse_source(self):
folder = filedialog.askdirectory(title="选择包含受保护Word文档的文件夹")
if folder:
self.source_folder.set(folder)
ifnotself.target_folder.get():
self.target_folder.set(folder)
defbrowse_target(self):
folder = filedialog.askdirectory(title="选择输出文件夹")
if folder:
self.target_folder.set(folder)
deflog(self, message):
self.log_text.config(state='normal')
self.log_text.insert(tk.END, message +"\n")
self.log_text.see(tk.END)
self.log_text.config(state='disabled')
self.root.update_idletasks()
defunprotect_word_document(self, file_path, output_path, password):
"""解除单个文档的保护"""
ifnot os.path.exists(file_path):
self.log(f"文件不存在: {file_path}")
returnFalse
word =None
try:
word = win32com.client.Dispatch("Word.Application")
word.Visible =False
doc = word.Documents.Open(file_path)
# 解除保护,需输入密码
doc.Unprotect(Password=password)
# 保存
if os.path.abspath(output_path) == os.path.abspath(file_path):
doc.Save()
else:
doc.SaveAs(output_path)
doc.Close()
self.log(f"✓ 已解除保护: {os.path.basename(file_path)}")
returnTrue
exceptExceptionas e:
# 如果密码错误,会在这里报错
error_msg =str(e)
if"password"in error_msg.lower() or"wrong"in error_msg.lower():
self.log(f"✗ 密码错误: {os.path.basename(file_path)}")
else:
self.log(f"✗ 处理失败: {os.path.basename(file_path)}, 错误: {e}")
returnFalse
finally:
if word isnotNone:
try:
word.Quit()
except:
pass
defprocess(self):
source =self.source_folder.get().strip()
target =self.target_folder.get().strip()
password =self.password.get().strip()
ifnot source ornot target:
messagebox.showwarning("警告", "请选择源文件夹和目标文件夹")
return
ifnot password:
messagebox.showwarning("警告", "请输入保护密码")
return
ifnot os.path.exists(source):
messagebox.showerror("错误", "源文件夹不存在")
return
ifnot os.path.exists(target):
try:
os.makedirs(target)
exceptExceptionas e:
messagebox.showerror("错误", f"无法创建目标文件夹: {e}")
return
extensions = ('.docx', '.doc')
files = [f for f in os.listdir(source) if f.lower().endswith(extensions)]
ifnot files:
messagebox.showinfo("提示", "未找到任何 Word 文档")
return
self.process_btn.config(state='disabled')
self.log_text.config(state='normal')
self.log_text.delete(1.0, tk.END)
self.log_text.config(state='disabled')
self.log(f"找到 {len(files)} 个文档,开始解除保护...")
success =0
for filename in files:
src_path = os.path.join(source, filename)
dst_path = os.path.join(target, filename)
ifself.unprotect_word_document(src_path, dst_path, password):
success +=1
self.log(f"\n处理完成!成功: {success}, 失败: {len(files) - success}")
self.process_btn.config(state='normal')
messagebox.showinfo("完成", f"共处理 {len(files)} 个文档,成功解除 {success} 个。")
if__name__=="__main__":
root = tk.Tk()
app = WordUnprotectorGUI(root)
root.mainloop()
夜雨聆风