
一、这个工具能帮你做什么?
打开程序后,你会看到一个下拉菜单,里面躺着 20 个功能,分成了五大类,覆盖了文员几乎所有的表格麻烦事:
📂 合并与拆分
| 序号 | 功能 | 适用场景 |
|---|---|---|
| 1 | 合并多个 Excel 文件 | 把同一文件夹内所有 .xlsx 竖着拼成一个总表 |
| 2 | 合并所有工作表 | 把一个工作簿里的多个 sheet 合成一个 |
| 3 | 按列拆分成多个文件 | 如按“区域”拆成《华东区.xlsx》《华南区.xlsx》 |
| 4 | 按列拆分到同一工作簿的不同 sheet | 拆开后还在一个文件里,方便查看 |
| 5 | 按行数拆分 | 大文件按每 500 行拆成多个小文件 |
📊 汇总与分析
| 序号 | 功能 | 适用场景 |
|---|---|---|
| 6 | 单列分类汇总 | 按部门汇总工资总和、按地区统计销售额 |
| 7 | 多列分组汇总 | 类似透视表,按“年份+区域”汇总金额 |
| 8 | 按条件筛选汇总 | 只统计“2025年”或“金额>1000”的记录 |
| 9 | 计算同比增长/环比 | 财务月报自动算增长率 |
🧹 数据清洗
| 序号 | 功能 | 适用场景 |
|---|---|---|
| 10 | 删除完全重复的行 | 快速去重 |
| 11 | 删除空行/空列 | 清理没有内容的行列 |
| 12 | 统一日期格式 | 把“2024.01.01”变成“2024-01-01” |
| 13 | 清除文本前后空格 | 姓名、地址多余空格一键去除 |
| 14 | 文本型数字转数值 | 把带绿三角的“数字”变成真正数字 |
🔗 匹配与查找
| 序号 | 功能 | 适用场景 |
|---|---|---|
| 15 | VLOOKUP 匹配 | 根据员工编号匹配姓名、根据商品编号匹配单价 |
| 16 | 找出两表差异 | 对比两个表格,标出哪些增加了、删除了、修改了 |
| 17 | 提取唯一值 | 从一列里拿出不重复的客户名单 |
🔄 格式转换
| 序号 | 功能 | 适用场景 |
|---|---|---|
| 18 | 批量 .xls 转 .xlsx | 旧版文件一键转新格式 |
| 19 | Excel ↔ CSV 互转 | 表格转 CSV,CSV 转回表格 |
| 20 | 提取工作表名称 | 把一个工作簿里所有 sheet 的名字列出来 |

二、完整代码(复制粘贴就能跑)
请确保你的电脑已安装 Python 和 pandas、openpyxl 库。如果没装,先打开命令行执行:
pip install pandas openpyxl然后把下面的代码完整复制到一个新建的 .py 文件里,例如 Excel工具箱.py,双击就能看到图形界面(或者用命令行 python Excel工具箱.py 运行)。
import pandas as pdimport osimport tkinter as tkfrom tkinter import ttk, messageboxfrom datetime import datetime# ============================================# 以下为 20 个功能的具体实现# 注意:所有功能均假设要处理的文件在“当前文件夹”下,# 文件名可以在每个函数中直接修改成你自己的。# ============================================def merge_files():"""1.合并当前文件夹下所有 .xlsx 文件(纵向拼接)"""folder = "." # 当前目录,可以把 "." 改成你的文件夹路径,如 "门店报表"files = [f for f in os.listdir(folder) if f.endswith('.xlsx') and not f.startswith('~')]if not files:return "没有找到任何 .xlsx 文件"all_data = []for f in files:df = pd.read_excel(f)all_data.append(df)result = pd.concat(all_data, ignore_index=True)result.to_excel("合并总表.xlsx", index=False)return f"合并完成,共处理 {len(files)} 个文件,结果保存为 合并总表.xlsx"def merge_sheets():"""2.合并一个工作簿的所有工作表到一个 sheet"""src_file = "待合并工作表.xlsx" # 改成你的源文件名if not os.path.exists(src_file):return f"找不到文件 {src_file}"xls = pd.ExcelFile(src_file)sheets = xls.sheet_namesall_data = []for sheet in sheets:df = pd.read_excel(src_file, sheet_name=sheet)df['来源工作表'] = sheet # 添加一列标记来源all_data.append(df)result = pd.concat(all_data, ignore_index=True)result.to_excel("合并所有工作表.xlsx", index=False)return f"已合并 {len(sheets)} 个工作表,结果保存为 合并所有工作表.xlsx"def split_by_col_to_files():"""3.按某列拆分,每个类保存为单独的 Excel 文件"""src_file = "源数据.xlsx" # 改成你的源文件split_col = "区域" # 改成你用于拆分的列名if not os.path.exists(src_file):return f"找不到 {src_file}"df = pd.read_excel(src_file)if split_col not in df.columns:return f"列 '{split_col}' 不存在,请检查"os.makedirs("拆分结果_文件", exist_ok=True)for value, group in df.groupby(split_col):safe_name = str(value).replace('/', '_').replace('\\', '_')group.to_excel(f"拆分结果_文件/{safe_name}.xlsx", index=False)return f"按 '{split_col}' 拆分完成,文件已存入 拆分结果_文件 文件夹"def split_by_col_to_sheets():"""4.按某列拆分,放到同一个工作簿的不同工作表里"""src_file = "源数据.xlsx"split_col = "区域"if not os.path.exists(src_file):return f"找不到 {src_file}"df = pd.read_excel(src_file)if split_col not in df.columns:return f"列 '{split_col}' 不存在"with pd.ExcelWriter("拆分结果_工作表.xlsx") as writer:for value, group in df.groupby(split_col):safe_name = str(value)[:31] # sheet名最长31字符group.to_excel(writer, sheet_name=safe_name, index=False)return "拆分完成,结果保存为 拆分结果_工作表.xlsx"def split_by_rows():"""5.按行数拆分,每 N 行存一个新文件"""src_file = "源数据.xlsx"rows_per_file = 1000 # 可自己修改if not os.path.exists(src_file):return f"找不到 {src_file}"df = pd.read_excel(src_file)os.makedirs("按行拆分结果", exist_ok=True)total = len(df)count = 0for i in range(0, total, rows_per_file):chunk = df.iloc[i:i+rows_per_file]chunk.to_excel(f"按行拆分结果/part_{i//rows_per_file + 1}.xlsx", index=False)count += 1return f"共拆分成 {count} 个文件,保存在 按行拆分结果 文件夹"def single_col_summary():"""6.单列分类汇总(求和/计数/平均)"""src_file = "源数据.xlsx"group_col = "部门" # 分组列value_col = "工资" # 汇总列agg_func = "sum" # 可选: sum, count, meanif not os.path.exists(src_file):return f"找不到 {src_file}"df = pd.read_excel(src_file)if group_col not in df.columns or value_col not in df.columns:return "指定的分组列或汇总列不存在"if agg_func == "sum":result = df.groupby(group_col, as_index=False)[value_col].sum()elif agg_func == "mean":result = df.groupby(group_col, as_index=False)[value_col].mean()else:result = df.groupby(group_col, as_index=False)[value_col].count()result.to_excel("单列汇总.xlsx", index=False)return f"按 '{group_col}' 对 '{value_col}' 进行 {agg_func} 完成,结果保存为 单列汇总.xlsx"def multi_col_summary():"""7.多列分组汇总(类似透视表)"""src_file = "源数据.xlsx"group_cols = ["区域", "产品"] # 可以改为你需要的分组列value_col = "销售额"if not os.path.exists(src_file):return f"找不到 {src_file}"df = pd.read_excel(src_file)for col in group_cols:if col not in df.columns:return f"列 '{col}' 不存在"result = df.groupby(group_cols, as_index=False)[value_col].sum()result.to_excel("多列分组汇总.xlsx", index=False)return "多列分组汇总完成,结果保存为 多列分组汇总.xlsx"def filter_summary():"""8.按条件筛选汇总"""src_file = "源数据.xlsx"filter_col = "年份"filter_value = 2025 # 修改为你的筛选条件value_col = "销售额"if not os.path.exists(src_file):return f"找不到 {src_file}"df = pd.read_excel(src_file)if filter_col not in df.columns:return f"列 '{filter_col}' 不存在"filtered = df[df[filter_col] == filter_value]if filtered.empty:return "没有满足条件的记录"total = filtered[value_col].sum()filtered.to_excel(f"筛选结果_{filter_value}.xlsx", index=False)return f"筛选出 {len(filtered)} 行,{value_col} 总和为 {total},结果已保存"def growth_rate():"""9.同比增长/环比计算(假设数据按时间排序,有'销售额'列)"""src_file = "月度数据.xlsx" # 必须包含“月份”和“销售额”列if not os.path.exists(src_file):return f"找不到 {src_file}"df = pd.read_excel(src_file)if "销售额" not in df.columns:return "缺少 '销售额' 列"df = df.sort_values("月份") # 假设有月份列,字符串格式可排序df["环比增长率"] = df["销售额"].pct_change()# 同比:如果按月,shift(12);按年,shift(1) 但要根据实际df["同比增长率"] = df["销售额"].pct_change(periods=12) # 假设每月数据df.to_excel("增长率计算.xlsx", index=False)return "增长率计算完成,结果保存为 增长率计算.xlsx"def remove_duplicates():"""10.删除完全重复的行"""src_file = "源数据.xlsx"subset_cols = None # None表示所有列完全重复才删除,可以改为 ["姓名","日期"] 指定列if not os.path.exists(src_file):return f"找不到 {src_file}"df = pd.read_excel(src_file)before = len(df)if subset_cols:df.drop_duplicates(subset=subset_cols, inplace=True)else:df.drop_duplicates(inplace=True)after = len(df)df.to_excel("去重结果.xlsx", index=False)return f"去重完成,从 {before} 行减少到 {after} 行,结果保存为 去重结果.xlsx"def remove_empty():"""11.删除空行和空列"""src_file = "源数据.xlsx"if not os.path.exists(src_file):return f"找不到 {src_file}"df = pd.read_excel(src_file)# 删除全为空的行df.dropna(how='all', inplace=True)# 删除全为空的列df.dropna(axis=1, how='all', inplace=True)df.to_excel("删除空行列结果.xlsx", index=False)return "空行和空列已删除,结果保存为 删除空行列结果.xlsx"def unify_date_format():"""12.统一日期格式为 YYYY-MM-DD"""src_file = "源数据.xlsx"date_col = "日期"if not os.path.exists(src_file):return f"找不到 {src_file}"df = pd.read_excel(src_file)if date_col not in df.columns:return f"列 '{date_col}' 不存在"# 尝试转换,忽略无法转换的df[date_col] = pd.to_datetime(df[date_col], errors='coerce').dt.strftime('%Y-%m-%d')df.to_excel("日期格式统一.xlsx", index=False)return "日期格式已统一为 YYYY-MM-DD,结果保存为 日期格式统一.xlsx"def strip_spaces():"""13.清除所有文本列的前后空格"""src_file = "源数据.xlsx"if not os.path.exists(src_file):return f"找不到 {src_file}"df = pd.read_excel(src_file)str_cols = df.select_dtypes(include='object').columnsfor col in str_cols:df[col] = df[col].astype(str).str.strip()df.to_excel("清除空格后.xlsx", index=False)return "文本空格已清除,结果保存为 清除空格后.xlsx"def text_to_number():"""14.将文本型数字转为数值"""src_file = "源数据.xlsx"col_name = "金额" # 改成你需要转换的列名if not os.path.exists(src_file):return f"找不到 {src_file}"df = pd.read_excel(src_file)if col_name not in df.columns:return f"列 '{col_name}' 不存在"# 先转字符串去掉千分位逗号,再转数字df[col_name] = df[col_name].astype(str).str.replace(',', '').str.replace(',', '')df[col_name] = pd.to_numeric(df[col_name], errors='coerce')df.to_excel("文本转数字.xlsx", index=False)return f"列 '{col_name}' 已转为数值,结果保存为 文本转数字.xlsx"def vlookup_match():"""15.VLOOKUP 匹配"""main_file = "主表.xlsx" # 需要查找的表lookup_file = "对照表.xlsx" # 被匹配的表on_col = "编号" # 两张表共有的列名return_cols = ["名称"] # 要从对照表拿过来的列if not os.path.exists(main_file) or not os.path.exists(lookup_file):return "主表或对照表文件不存在"main_df = pd.read_excel(main_file)lookup_df = pd.read_excel(lookup_file)if on_col not in main_df.columns or on_col not in lookup_df.columns:return f"列 '{on_col}' 在某张表中不存在"# 只取对照表中需要的列,去重保留第一个lookup_sub = lookup_df[[on_col] + return_cols].drop_duplicates(subset=on_col)result = main_df.merge(lookup_sub, on=on_col, how='left')result.to_excel("VLOOKUP结果.xlsx", index=False)return "VLOOKUP 匹配完成,结果保存为 VLOOKUP结果.xlsx"def compare_two_sheets():"""16.找出两表差异"""old_file = "旧表.xlsx"new_file = "新表.xlsx"key_col = "编号" # 用于比较的主键列if not os.path.exists(old_file) or not os.path.exists(new_file):return "旧表或新表文件不存在"old_df = pd.read_excel(old_file)new_df = pd.read_excel(new_file)if key_col not in old_df.columns or key_col not in new_df.columns:return f"列 '{key_col}' 在某表中不存在"old_ids = set(old_df[key_col])new_ids = set(new_df[key_col])added = new_df[new_df[key_col].isin(new_ids - old_ids)]deleted = old_df[old_df[key_col].isin(old_ids - new_ids)]# 修改的:主键相同但其他列不同common_ids = old_ids & new_idsold_common = old_df[old_df[key_col].isin(common_ids)].set_index(key_col)new_common = new_df[new_df[key_col].isin(common_ids)].set_index(key_col)# 简单比较,找出不相等的行(需要列名完全一致)diff_mask = (old_common != new_common).any(axis=1)modified_old = old_common[diff_mask].reset_index()modified_new = new_common[diff_mask].reset_index()with pd.ExcelWriter("两表差异.xlsx") as writer:added.to_excel(writer, sheet_name="新增行", index=False)deleted.to_excel(writer, sheet_name="删除行", index=False)modified_old.to_excel(writer, sheet_name="修改前", index=False)modified_new.to_excel(writer, sheet_name="修改后", index=False)return "差异分析完成,结果保存为 两表差异.xlsx"def unique_values():"""17.提取指定列的唯一值"""src_file = "源数据.xlsx"col = "客户名称"if not os.path.exists(src_file):return f"找不到 {src_file}"df = pd.read_excel(src_file)if col not in df.columns:return f"列 '{col}' 不存在"unique_list = df[col].drop_duplicates().reset_index(drop=True)unique_list.to_excel("唯一值列表.xlsx", index=False)return f"已提取 '{col}' 列的唯一值,共 {len(unique_list)} 个,保存为 唯一值列表.xlsx"def batch_xls_to_xlsx():"""18.批量将当前目录下所有 .xls 转为 .xlsx"""import globfiles = glob.glob("*.xls")if not files:return "当前文件夹没有 .xls 文件"count = 0for f in files:if f.startswith('~'): # 忽略临时文件continue# 使用 xlrd 读取 .xls,需要安装 pip install xlrdtry:df = pd.read_excel(f)df.to_excel(f + "x", index=False) # 新文件名在原文件名后加 xcount += 1except Exception as e:print(f"转换 {f} 失败:{e}")return f"转换完成,共处理 {count} 个文件,新文件为 .xlsx 后缀"def excel_csv_conversion():"""19.Excel 与 CSV 互转(当前示例:Excel 转 CSV)"""src_file = "源数据.xlsx"if not os.path.exists(src_file):return f"找不到 {src_file}"df = pd.read_excel(src_file)csv_file = "转换结果.csv"df.to_csv(csv_file, index=False, encoding='utf-8-sig') # 防止中文乱码return f"已转换为 CSV,保存为 {csv_file}"# 若需 CSV 转 Excel,可类似:df = pd.read_csv('xxx.csv'); df.to_excel('xxx.xlsx', index=False)def list_sheet_names():"""20.提取工作簿的所有工作表名称"""src_file = "待查看.xlsx"if not os.path.exists(src_file):return f"找不到 {src_file}"xls = pd.ExcelFile(src_file)sheets = xls.sheet_namesdf = pd.DataFrame({"工作表名": sheets})df.to_excel("工作表名称列表.xlsx", index=False)return f"该文件共有 {len(sheets)} 个工作表,名称已保存至 工作表名称列表.xlsx"# ============================================# 图形界面部分# ============================================func_map = {"1-合并多个Excel文件": merge_files,"2-合并所有工作表": merge_sheets,"3-按列拆分成多个文件": split_by_col_to_files,"4-按列拆分到同一工作簿的不同sheet": split_by_col_to_sheets,"5-按行数拆分": split_by_rows,"6-单列分类汇总": single_col_summary,"7-多列分组汇总": multi_col_summary,"8-按条件筛选汇总": filter_summary,"9-同比增长/环比计算": growth_rate,"10-删除完全重复的行": remove_duplicates,"11-删除空行/空列": remove_empty,"12-统一日期格式": unify_date_format,"13-清除文本前后空格": strip_spaces,"14-文本型数字转数值": text_to_number,"15-VLOOKUP匹配": vlookup_match,"16-找出两表差异": compare_two_sheets,"17-提取唯一值": unique_values,"18-批量xls转xlsx": batch_xls_to_xlsx,"19-Excel与CSV互转(示例:转CSV)": excel_csv_conversion,"20-提取工作表名称": list_sheet_names,}def execute():selected = combo.get()if selected in func_map:try:msg = func_map[selected]()messagebox.showinfo("完成", msg)except Exception as e:messagebox.showerror("出错了", f"执行失败:{str(e)}")else:messagebox.showwarning("提示", "请先选择一个功能")# 创建窗口root = tk.Tk()root.title("Excel 全能工具箱 (20合1)")root.geometry("520x220")root.resizable(False, False)ttk.Label(root, text="请选择要执行的功能:", font=("微软雅黑", 12)).pack(pady=15)combo = ttk.Combobox(root, values=list(func_map.keys()), width=50, state="readonly")combo.pack(pady=10)combo.current(0)ttk.Button(root, text="▶ 开始处理", command=execute).pack(pady=20)ttk.Label(root, text="提示:请根据实际表格修改代码中的文件名和列名", foreground="gray").pack()root.mainloop()

三、如何让代码变成你自己的专属工具?
上面的代码直接复制就可以跑,但里面的文件名和列名都是我假设的。要让它真正为你工作,只需要简单改几个地方:
修改文件名:每个函数开头的 src_file = "源数据.xlsx" 改成你电脑上实际的文件名。
修改列名:例如 split_col = "区域" 改成你表格里的“销售地区”;value_col = "销售额" 改成“金额”等。
调整参数:比如拆分行数 rows_per_file = 1000 可以改成 500;筛选条件 filter_value = 2025 改成你需要的年份。
改完后保存,重新运行即可。

四、打包成 exe,发给没有 Python 的同事
这一步只需要做一次,你(或请 IT 同事)打包后,其他人就能双击使用。
1、在存放 Excel工具箱.py 的文件夹地址栏输入 cmd 回车,打开命令行。
2、输入以下命令打包(-F 生成单个文件,-w 不显示黑窗口):
pyinstaller -F -w Excel工具箱.py3、等待一分钟左右,在自动生成的 dist 文件夹里找到 Excel工具箱.exe,这就是最终程序。
把这个 exe 复制到任何 Windows 电脑上,不需要安装 Python,不需要配置环境,直接双击就能看到那个下拉菜单,选功能、点按钮,几秒钟结果就出来了。
⚠️ 重要说明:exe 运行时会读取它所在文件夹里的 Excel 文件,所以需要把要处理的表格和 exe 放在同一个文件夹下(或者在代码里写明完整路径)。

五、写在最后
这 20 个功能几乎覆盖了日常办公中 90% 的 Excel 重复劳动,更重要的是,你拥有的是一个完全自定义、可以无限扩展的框架。以后有了新需求,只需仿照格式加一个新函数,在 func_map 里注册一下,重新打包就行。

商务合作:RYXtest
夜雨聆风