查看: 134|回复: 3

Python xlwings批量合并Excel多工作簿同名工作表:表头只取一次

[复制链接]
发表于 2 小时前 | 显示全部楼层 |阅读模式
在办公自动化中,经常需要将多个Excel工作簿中相同名称的工作表合并成一个汇总表。比如华北、华东、华南各分部提交的“上半年.xlsx”文件中都有一张名为“统计”的工作表,最终需要汇总到“上半年汇总表.xlsx”里。手工操作需要反复打开、复制、粘贴,效率低且容易出错。使用Python配合xlwings库可以稳定地批量处理这类任务。

核心思路是:遍历目标文件夹中的所有Excel文件,对每个文件检查是否存在指定名称的工作表,如果存在则提取其数据。第一次读取时保留表头(第一行),后续文件只追加数据行(第二行开始),最终将表头和数据写入一个新的汇总工作簿。

下面是一份可直接使用的完整代码,只需修改三个参数:输入文件夹路径、目标工作表名称、输出文件路径。
  1. import os
  2. import xlwings as xw
  3. # 需要根据实际修改的参数
  4. folder_path = r"e:\file\target"      # 多个工作簿所在目录
  5. sheet_name = "统计"                    # 需要合并的同名工作表
  6. out_file = r"e:\file\上半年汇总表.xlsx" # 输出汇总文件
  7. app = xw.App(visible=False, add_book=False)
  8. header = None
  9. all_data = []
  10. try:
  11.     for file in os.listdir(folder_path):
  12.         # 1. 跳过Excel临时文件
  13.         if file.startswith("~$"):
  14.             continue
  15.         # 2. 只处理Excel文件
  16.         if not file.lower().endswith((".xlsx", ".xls", ".xlsm")):
  17.             continue
  18.         full_path = os.path.join(folder_path, file)
  19.         wb = app.books.open(full_path)
  20.         # 3. 判断目标工作表是否存在
  21.         sheet_names = [s.name for s in wb.sheets]
  22.         if sheet_name not in sheet_names:
  23.             wb.close()
  24.             print(f"跳过:{file},不存在工作表:{sheet_name}")
  25.             continue
  26.         sht = wb.sheets[sheet_name]
  27.         # 4. 从A1开始扩展读取连续数据区域
  28.         table = sht.range("A1").expand("table").value
  29.         # 5. 判断是否有有效数据(至少包含表头+一行数据)
  30.         if not table or len(table) < 2:
  31.             wb.close()
  32.             print(f"跳过:{file},数据为空或只有表头")
  33.             continue
  34.         # 6. 第一次读取时记录表头
  35.         if header is None:
  36.             header = table[0]
  37.         # 7. 后续只累积数据行
  38.         values = table[1:]
  39.         all_data = all_data + values
  40.         wb.close()
  41.         print(f"已读取:{file} -> [{sheet_name}]")
  42.     # 8. 新建汇总工作簿
  43.     out_wb = app.books.add()
  44.     out_sht = out_wb.sheets[0]
  45.     out_sht.name = "汇总"
  46.     if header is None:
  47.         out_sht.range("A1").value = [["没有读取到任何有效数据"]]
  48.     else:
  49.         out_sht.range("A1").value = [header] + all_data
  50.     out_sht.autofit()
  51.     out_wb.save(out_file)
  52.     out_wb.close()
  53.     print(f"汇总完成:{out_file}")
  54. finally:
  55.     app.quit()
复制代码

关键代码详解:
- 跳过临时文件:Excel打开时可能产生~$开头的临时文件,不跳过会报错。用 startswith("~$") 判断。
- 判断工作表是否存在:通过 [s.name for s in wb.sheets] 获取工作表名列表,若目标名不在其中则跳过该文件。
- expand("table"):从A1开始自动扩展读取连续数据区域,前提是表格从A1附近开始且中间无空行/合并单元格。
- autofit():写入数据后自动调整列宽,方便直接查看。

常见踩坑提醒:
- 表头不一致:不同文件字段名或顺序不同,合并后数据会错位。建议合并前校验表头是否一致:if header is not None and table[0] != header: print(f"表头不一致:{file}")
- 空行和合并单元格:影响 expand 读取范围,建议先统一模板再处理。
- 文件被打开:源文件或输出文件正在使用会导致保存失败,最好将文件复制到本地临时目录操作。
- xlwings依赖Excel环境:需要本机安装Excel,否则无法运行。若需无界面处理,可改用 pandas+openpyxl。

扩展应用:同样的思路适用于一个工作簿内合并多个工作表,例如“年度数据.xlsx”中的1月~6月合并为“上半年汇总”。只需将遍历文件改为遍历工作表列表(month_sheets = ["1月","2月",...]),其他逻辑不变。

批量合并前务必备份源文件,并用少量样本测试结果。对于财务、库存等关键数据,跑稳比跑快更重要。
回复

使用道具 举报

发表于 2 小时前 | 显示全部楼层

Re: Python xlwings批量合并Excel多工作簿同名工作表:表头只取一次

谢谢分享,这个脚本很实用!之前手动合并过类似的分部报表,确实容易漏掉或弄错行。代码里跳过临时文件和判断工作表是否存在这两点特别贴心,还有自动调整列宽,省了不少后续整理的时间。请问如果多个文件的表头顺序不完全一致,您一般是怎么处理的?是提前强制统一模板,还是在合并前做个表头检查然后报错提醒?
回复 支持 反对

使用道具 举报

发表于 2 小时前 | 显示全部楼层

Re: Python xlwings批量合并Excel多工作簿同名工作表:表头只取一次

楼主分享的代码很实用,正好解决了多工作簿同名工作表合并的痛点。`expand("table")` 和跳过临时文件的细节处理得很到位,能避免不少坑。建议在合并前增加表头一致性校验那一步,实测能提前发现模板不统一的文件。另外想请教下,如果不同工作簿的列顺序不同,除了校验外还有什么好的预处理方式?
回复 支持 反对

使用道具 举报

发表于 2 小时前 | 显示全部楼层

Re: Python xlwings批量合并Excel多工作簿同名工作表:表头只取一次

楼主分享的脚本很实用,我正好在处理类似的分部报表汇总工作。之前一直用VBA,但跨平台兼容性差,改用Python后确实稳定很多。注意到你特别强调了表头只取一次,这点很关键,不然合并后全是重复标题行。我准备在自己的场景里试试,顺便加个表头校验的提示,防止不同部门字段顺序不一样导致数据错位。另外想问一下,如果源文件中有空行或者合并单元格,这个 `expand("table")` 会受影响吗?有没有建议的预处理步骤?
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

指导单位

江苏省公安厅

江苏省通信管理局

浙江省台州刑侦支队

DEFCON GROUP 86025

Hacking Group 021A

旗下站点

态势感知中心

应急响应中心

红盟安全

联系我们

官方QQ群:112851260

官方邮箱:security#ihonker.org(#改成@)

官方核心成员

关注微信公众号

Archiver|手机版|小黑屋| ( 沪ICP备2021026908号 )

GMT+8, 2026-6-30 12:34 , Processed in 0.037914 second(s), 17 queries , Gzip On, Redis On.

Powered by ihonker.com

Copyright © 2015-现在.

  • 返回顶部