基于 Tkinter 的 Excel 文件差异对比工具,核心要求是通过 pandas.merge 外连接实现数据比对、用 openpyxl 给差异单元格标红、最终生成带样式的变更报告和数据汇总统计。



下面为你提供一个完整、可直接运行的实现方案,包含所有核心功能。
首先安装所需依赖库,打开终端执行以下命令:
pip install tkinter pandas openpyxl注意:tkinter 在 Python 3 中通常自带,若缺失请根据你的系统单独安装(Windows 一般自带,Linux 可执行
sudo apt install python3-tk)。
import tkinter as tkfrom tkinter import filedialog, messageboximport pandas as pdfrom openpyxl import load_workbookfrom openpyxl.styles import PatternFillfrom datetime import datetimeclassExcelDiffTool:def__init__(self, root):"""初始化GUI界面和变量""" self.root = root self.root.title("Excel 数据差异对比工具") self.root.geometry("600x300")# 存储两个Excel文件路径 self.file1_path = tk.StringVar() self.file2_path = tk.StringVar()# 构建GUI控件 self._build_gui()def_build_gui(self):"""构建Tkinter图形界面"""# 第一个文件选择区域 frame1 = tk.Frame(self.root, pady=10) frame1.pack(fill=tk.X, padx=20) tk.Label(frame1, text="原始Excel文件:").pack(side=tk.LEFT) tk.Entry(frame1, textvariable=self.file1_path, width=50).pack(side=tk.LEFT, padx=10) tk.Button(frame1, text="浏览", command=lambda: self._select_file(self.file1_path)).pack(side=tk.LEFT)# 第二个文件选择区域 frame2 = tk.Frame(self.root, pady=10) frame2.pack(fill=tk.X, padx=20) tk.Label(frame2, text="对比Excel文件:").pack(side=tk.LEFT) tk.Entry(frame2, textvariable=self.file2_path, width=50).pack(side=tk.LEFT, padx=10) tk.Button(frame2, text="浏览", command=lambda: self._select_file(self.file2_path)).pack(side=tk.LEFT)# 执行对比按钮 tk.Button(self.root, text="开始差异对比", command=self._execute_excel_diff, bg="#4CAF50", fg="white", padx=10, pady=5).pack(pady=30)def_select_file(self, var):"""打开文件选择对话框,选择Excel文件""" file_path = filedialog.askopenfilename( title="选择Excel文件", filetypes=(("Excel文件", "*.xlsx;*.xls"), ("所有文件", "*.*")) )if file_path: var.set(file_path)def_execute_excel_diff(self):"""核心执行逻辑:读取Excel、数据比对、标红差异、生成报告""" file1 = self.file1_path.get() file2 = self.file2_path.get()# 校验文件路径ifnot file1 ornot file2: messagebox.showwarning("警告", "请先选择两个Excel文件!")returnif file1 == file2: messagebox.showwarning("警告", "请选择两个不同的Excel文件!")returntry:# 1. 读取Excel数据(默认读取第一个工作表) df1 = pd.read_excel(file1, engine="openpyxl") df2 = pd.read_excel(file2, engine="openpyxl")# 校验数据是否为空if df1.empty or df2.empty: messagebox.showwarning("警告", "所选Excel文件中存在空数据!")return# 2. 用pandas.merge外连接比对数据(默认以所有列作为关联键,可根据需求修改)# 先添加来源标识列 df1["_data_source_"] = "原始文件" df2["_data_source_"] = "对比文件"# 外连接比对 merged_df = pd.merge(df1, df2, how="outer", indicator=True, suffixes=("_原始", "_对比"))# 3. 生成差异数据、变更报告和汇总统计 diff_result, summary_stats = self._analyze_diff_data(merged_df)# 4. 保存变更报告并给差异单元格标红 report_filename = f"Excel差异变更报告_{datetime.now().strftime('%Y%m%d_%H%M%S')}.xlsx" self._save_diff_report_with_style(diff_result, report_filename, df1.columns)# 5. 弹出完成提示,展示汇总统计 summary_info = "\n".join([f"{k}:{v}"for k, v in summary_stats.items()]) messagebox.showinfo("完成", f"差异对比已完成!\n\n汇总统计:\n{summary_info}\n\n变更报告已保存为:\n{report_filename}")except Exception as e: messagebox.showerror("错误", f"执行过程中出现异常:\n{str(e)}")def_analyze_diff_data(self, merged_df):"""分析比对结果,提取差异数据和生成汇总统计"""# 提取差异数据(仅保留非"both"的记录,即仅在原始文件/仅在对比文件/数据不一致) diff_df = merged_df[merged_df["_merge"] != "both"].copy()# 汇总统计 summary_stats = {"原始文件数据行数": len(merged_df[merged_df["_merge"] == "left_only"]) + len(merged_df[merged_df["_merge"] == "both"]),"对比文件数据行数": len(merged_df[merged_df["_merge"] == "right_only"]) + len(merged_df[merged_df["_merge"] == "both"]),"仅在原始文件存在的行数": len(merged_df[merged_df["_merge"] == "left_only"]),"仅在对比文件存在的行数": len(merged_df[merged_df["_merge"] == "right_only"]),"双方共有但数据不一致的行数": len(merged_df[merged_df["_merge"] == "both"]) - len(merged_df[merged_df.duplicated()]),"总差异行数": len(diff_df) }# 清理辅助列(可选,根据需求保留) diff_df = diff_df.drop(columns=["_merge"], errors="ignore")return diff_df, summary_statsdef_save_diff_report_with_style(self, diff_df, filename, original_columns):"""保存变更报告,并用openpyxl给差异单元格填充红色背景"""# 1. 先将差异数据保存为Excel文件 diff_df.to_excel(filename, index=False, engine="openpyxl")# 2. 用openpyxl加载文件,准备设置单元格样式 wb = load_workbook(filename) ws = wb.active# 定义红色填充样式(差异单元格背景) red_fill = PatternFill(start_color="FFFF0000", end_color="FFFF0000", fill_type="solid")# 3. 遍历单元格,标记差异(核心:对比原始列和对比列的数值)# 获取所有带后缀的列名 original_cols = [col + "_原始"for col in original_columns if col + "_原始"in diff_df.columns] compare_cols = [col + "_对比"for col in original_columns if col + "_对比"in diff_df.columns]# 列名映射(原始列 ↔ 对比列) col_pair = list(zip(original_cols, compare_cols))# 遍历数据行(从第2行开始,第1行是表头)for row in range(2, ws.max_row + 1):# 遍历每一对原始/对比列for orig_col, comp_col in col_pair:# 获取列的字母标识(如A、B、C...) orig_col_letter = ws[orig_col].column_letter if orig_col in ws elseNone comp_col_letter = ws[comp_col].column_letter if comp_col in ws elseNoneif orig_col_letter and comp_col_letter:# 获取单元格值 cell_orig = ws[f"{orig_col_letter}{row}"] cell_comp = ws[f"{comp_col_letter}{row}"]# 标记差异:值不相等且都不为空(或其中一个为空)if cell_orig.value != cell_comp.value: cell_orig.fill = red_fill cell_comp.fill = red_fill# 4. 保存带样式的Excel文件 wb.save(filename)if __name__ == "__main__": root = tk.Tk() app = ExcelDiffTool(root) root.mainloop().xlsx/.xls 格式的 Excel 文件pd.read_excel 读取 Excel 数据,指定 engine="openpyxl" 兼容 .xlsx 格式pd.merge(how="outer", indicator=True) 实现外连接比对_merge 列标记数据来源:left_only(仅原始文件)、right_only(仅对比文件)、both(双方共有)openpyxl 加载文件进行样式修改PatternFill 红色填充样式,遍历原始列和对比列的对应单元格pd.read_excel 中的 sheet_name 参数(如 sheet_name="Sheet2")pd.merge 中的 on 参数(如 on=["ID", "姓名"]).xlsx 格式文件,.xls 格式需要额外安装 xlrd 库(pip install xlrd==1.2.0)Tkinter 实现可视化文件选择,核心依赖 pandas.merge 外连接完成数据比对,openpyxl 实现差异单元格标红。on 参数)、工作表(sheet_name 参数),适配不同格式的 Excel 数据。