《超简单:用 Python 让 Excel 飞起来》读书笔记:第4章 案例09 批量合并多个工作簿中的同名工作表

发布时间:2026/6/24 12:59:33
《超简单:用 Python 让 Excel 飞起来》读书笔记:第4章 案例09 批量合并多个工作簿中的同名工作表 个人主页杨利杰YJlio❄️个人专栏《Sysinternals实战教程》 《Windows PowerShell 实战》 《WINDOWS教程》 《IOS教程》《微信助手》 《锤子助手》 《Python》 《Kali Linux》《那些年未解决的Windows疑难杂症》让复杂的事情更简单让重复的工作自动化《超简单用 Python 让 Excel 飞起来》读书笔记第4章 案例09 批量合并多个工作簿中的同名工作表1. 问题背景为什么要批量合并同名工作表2. 应用场景多个分部统计表合成一份汇总表3. 核心原理表头只取一次数据持续累积4. 实现流程遍历文件、读取同名表、写入汇总簿5. 关键代码拆解为什么这样写5.1 为什么要跳过临时文件5.2 为什么要判断同名工作表是否存在5.3 为什么用 expand(table)5.4 为什么最后要 autofit()6. 效果验证汇总后必须检查这几项7. 常见问题与踩坑提醒7.1 表头不一致会导致汇总结果变脏7.2 空行和合并单元格会影响读取范围7.3 文件被打开可能导致保存异常7.4 xlwings 依赖 Excel 环境8. 举一反三一个工作簿内合并 1月 到 6月9. 总结提升合并不是复制合并是规则化处理1. 问题背景为什么要批量合并同名工作表这一篇继续整理《超简单用 Python 让 Excel 飞起来》第 4 章中的案例内容主题是批量合并多个工作簿中的同名工作表。这个场景在真实办公里很常见多个部门、多个分部、多个项目分别提交 Excel 文件每个文件里都有一张同名工作表最后需要汇总成一份总表。比如华北、华东、华南三个分部各自提交一个上半年.xlsx文件每个文件里都有一张叫统计的工作表。现在领导不想看三个文件只想看一份上半年汇总表.xlsx。如果手工处理就要不断打开文件、复制数据、粘贴到总表这就是非常典型的“复制粘贴型加班”。这张图展示的是本文的整体目标把多个工作簿中的同名工作表批量合并到一个新的汇总工作簿中。从图中可以看出本文的重点不是处理单个 Excel而是把多个来源文件的数据统一汇入一个结果文件。这类任务的核心不是“会不会复制”而是能不能稳定地批量读取、累积数据、生成汇总结果。这里最容易翻车的地方是把每个工作簿的表头都一起复制进去。如果每合并一个文件就追加一次表头最后的汇总表里会反复出现“日期、产品、销量、金额”这样的标题行后续筛选、排序、透视分析都会受到影响。2. 应用场景多个分部统计表合成一份汇总表批量合并同名工作表本质上解决的是“分散数据集中化”的问题。只要多个 Excel 文件结构相似且目标工作表名称一致就可以考虑用脚本自动合并。这张图展示的是典型应用场景多个分部统计表最终汇总成一份总表。从图中可以看到这类需求常见于财务汇总、销售汇总、库存汇总等场景。每个分部都有自己的统计表但管理层真正需要的是一份统一结果。Python 在这里的价值就是把重复复制粘贴变成稳定规则。我更建议把这类任务理解成一个标准流程先确定文件夹再逐个打开工作簿找到指定同名工作表读取数据持续累积最后统一写入一个新的汇总工作簿。不存在存在多个分部Excel文件遍历文件夹打开当前工作簿是否存在同名工作表跳过当前文件读取表格数据第一次读取表头后续只追加数据累积到 all_data写入新汇总工作簿这张流程图里最重要的是两个判断第一目标工作表是否存在第二当前是不是第一次读取数据。前者决定文件要不要跳过后者决定是否要读取表头。3. 核心原理表头只取一次数据持续累积批量合并多个工作簿时最关键的逻辑不是打开文件而是处理表头和数据的关系。正常情况下每个工作簿里的同名工作表都有一行表头但最终汇总表只需要一份表头。这张图展示的是本案例的核心逻辑第一次读取时保留表头后续工作簿只追加数据行。从图中可以看出header None表示表头还没有被初始化all_data []表示先准备一个空列表用来持续累积后续读取到的数据行。第一次遇到有效表格时取出表头之后每读取一个文件就只把数据部分追加到all_data中。header None的语义是“还没有拿到表头”而不是“表头为空”。这个区别很重要。None更像一个初始化标记表示后面第一次读取到表格时需要把第一行保存为表头。headerNoneall_data[]ifheaderisNone:headertable[0]valuestable[1:]all_dataall_datavalues这里的table[0]表示第一行也就是表头table[1:]表示从第二行开始的所有数据行。最终写入汇总表时用[header] all_data拼成完整内容。如果不区分表头和数据汇总表后期会很难用。重复表头会影响筛选、排序、透视表、公式引用也会让数据看起来不干净。这种问题不是语法错误但属于典型的数据质量问题。4. 实现流程遍历文件、读取同名表、写入汇总簿在看完整代码之前先把流程想清楚。这个案例可以拆成八个动作遍历文件夹、跳过临时文件、检查是否存在目标工作表、读取表格数据、累积到all_data、新建汇总工作簿、写入表头和数据、最后执行autofit()自动调整显示效果。这张图展示的是完整实现流程从文件遍历一直到最终生成汇总表。从图中可以看出真正稳定的脚本不是“打开文件然后复制”而是每一步都有判断。比如遇到~$临时文件要跳过目标工作表不存在要跳过数据为空也要跳过。批处理脚本越是面对多个文件越不能假设每个文件都完全正常。下面是一份可直接修改使用的完整代码。实际使用时只需要改三个参数输入文件夹、目标工作表名称、输出文件路径。importosimportxlwingsasxw# 需要根据实际情况修改的参数 folder_pathre:\file\target# 多个工作簿所在目录sheet_name统计# 需要合并的同名工作表out_filere:\file\上半年汇总表.xlsx# 输出汇总文件# appxw.App(visibleFalse,add_bookFalse)headerNoneall_data[]try:forfileinos.listdir(folder_path):# 1. 跳过 Excel 临时文件iffile.startswith(~$):continue# 2. 只处理 Excel 文件ifnotfile.lower().endswith((.xlsx,.xls,.xlsm)):continuefull_pathos.path.join(folder_path,file)wbapp.books.open(full_path)# 3. 判断目标工作表是否存在sheet_names[s.nameforsinwb.sheets]ifsheet_namenotinsheet_names:wb.close()print(f跳过{file}不存在工作表{sheet_name})continueshtwb.sheets[sheet_name]# 4. 从 A1 开始扩展读取表格区域tablesht.range(A1).expand(table).value# 5. 判断是否有有效数据ifnottableorlen(table)2:wb.close()print(f跳过{file}数据为空或只有表头)continue# 6. 第一次读取表头ifheaderisNone:headertable[0]# 7. 后续只累积数据行valuestable[1:]all_dataall_datavalues wb.close()print(f已读取{file}- [{sheet_name}])# 8. 新建汇总工作簿out_wbapp.books.add()out_shtout_wb.sheets[0]out_sht.name汇总ifheaderisNone:out_sht.range(A1).value[[没有读取到任何有效数据]]else:out_sht.range(A1).value[header]all_data out_sht.autofit()out_wb.save(out_file)out_wb.close()print(f汇总完成{out_file})finally:app.quit()这段代码的骨架很清楚外层负责遍历文件内层负责读取指定工作表最后统一写入汇总工作簿。它不是一次性脚本而是一个可以复用的批量合并模板。5. 关键代码拆解为什么这样写5.1 为什么要跳过临时文件Excel 打开文件时目录里可能出现~$开头的临时文件。这类文件不是正式工作簿脚本如果尝试打开它很容易报错。iffile.startswith(~$):continue推荐所有批量处理 Excel 的脚本都加上这个判断。这不是多余代码而是稳定性保障。5.2 为什么要判断同名工作表是否存在并不是所有文件都一定有目标工作表。比如有些分部没有提交统计表或者表名写成了数据统计。如果不判断直接读取就会报错。sheet_names[s.nameforsinwb.sheets]ifsheet_namenotinsheet_names:wb.close()print(f跳过{file}不存在工作表{sheet_name})continue不要默认所有文件都符合模板。真实办公里文件命名、sheet 命名、字段顺序经常会有偏差。脚本必须允许异常文件跳过而不是因为一个文件异常导致整个任务中断。5.3 为什么用 expand(“table”)sht.range(A1).expand(table).value的意思是从A1单元格开始自动扩展读取连续的数据区域。只要表格从A1开始并且中间没有完全空白行列这种写法就比较方便。tablesht.range(A1).expand(table).value这里有一个前提表格必须从 A1 附近开始并且数据区域要连续。如果表格上方有标题说明、空行、合并单元格expand(table)可能无法读到你想要的区域。这类文件需要先规范模板或者改用更明确的读取范围。5.4 为什么最后要 autofit()写入 Excel 后列宽可能不合适长文本会被遮住数字也可能显示成#######。所以写完数据后执行autofit()能让汇总表更接近可阅读状态。out_sht.autofit()推荐在生成结果文件时做基础美化。办公自动化不是只把数据写进去还要考虑别人打开文件时能不能直接看。6. 效果验证汇总后必须检查这几项批量合并脚本跑完后不能只看控制台有没有报错。更稳的做法是对输出结果做基本校验。第一要检查输出文件是否生成第二要检查汇总表是否只有一行表头第三要检查数据行数是否符合预期第四要抽查几条来源数据看是否确实进入汇总表。print(f汇总数据行数{len(all_data)})print(f输出文件{out_file})如果希望日志更清楚可以记录每个文件的处理状态。比如哪些文件成功读取哪些文件缺少目标 sheet哪些文件为空。这样后续复盘更方便。log_list[]log_list.append({文件名:file,目标工作表:sheet_name,处理结果:已读取,数据行数:len(values)})对于真实办公场景我更建议把处理日志也导出成 Excel。因为脚本输出的结果文件可能会被别人复查处理日志就是你的证据链。7. 常见问题与踩坑提醒7.1 表头不一致会导致汇总结果变脏如果不同工作簿里的统计表字段不一致比如有的叫销售额有的叫金额脚本虽然可能能合并但最终结果会出现字段含义不统一的问题。合并前最好先校验表头是否一致。否则看起来合并成功实际数据口径可能已经错了。ifheaderisnotNoneandtable[0]!header:print(f表头不一致{file})7.2 空行和合并单元格会影响读取范围expand(table)适合连续表格。如果 Excel 里有空行、合并单元格、额外标题、说明文字读取范围可能不符合预期。推荐先统一模板再批量合并。如果模板混乱脚本只是把混乱放大不能自动把所有脏数据变干净。7.3 文件被打开可能导致保存异常如果某个源文件正在被打开或者输出汇总文件已经被打开脚本可能无法保存。尤其是在共享盘、同步盘、企业网盘目录中这个问题很常见。建议先把待处理文件复制到本地临时目录例如C:\Temp\excel_merge确认无人占用后再执行脚本。7.4 xlwings 依赖 Excel 环境xlwings的优势是能像人工一样操作 Excel但它通常依赖本机安装的 Excel。如果电脑没有安装 Excel或者 Excel 插件、弹窗、权限策略异常脚本也可能运行失败。如果只是读取和合并数据后续也可以考虑用 pandas openpyxl 做无界面处理。但本文沿用书中思路重点练习的是 xlwings 操控工作簿和工作表的能力。8. 举一反三一个工作簿内合并 1月 到 6月前面的案例是多个工作簿合并到一个汇总簿。其实同样的思路也可以用于一个工作簿内部比如一个年度数据.xlsx中有1月、2月、3月、4月、5月、6月这些工作表现在要合并成一张上半年汇总。这张图展示的是扩展案例在同一个工作簿中把 1月 到 6月 的工作表合并到一张新表中。从图中可以看出虽然合并范围从“多个文件”变成了“一个文件里的多个 sheet”但底层逻辑没有变第一次取表头后续只取数据最后写入新的汇总工作表。importxlwingsasxw file_pathre:\file\年度数据.xlsxmonth_sheets[1月,2月,3月,4月,5月,6月]appxw.App(visibleFalse,add_bookFalse)headerNoneall_data[]try:wbapp.books.open(file_path)fornameinmonth_sheets:sheet_names[s.nameforsinwb.sheets]ifnamenotinsheet_names:print(f跳过不存在工作表{name})continueshtwb.sheets[name]tablesht.range(A1).expand(table).valueifnottableorlen(table)2:print(f跳过{name}数据为空或只有表头)continueifheaderisNone:headertable[0]all_dataall_datatable[1:]if上半年汇总notin[s.nameforsinwb.sheets]:wb.sheets.add(上半年汇总)sum_shtwb.sheets[上半年汇总]sum_sht.clear()ifheaderisNone:sum_sht.range(A1).value[[没有读取到任何有效数据]]else:sum_sht.range(A1).value[header]all_data sum_sht.autofit()wb.save()wb.close()finally:app.quit()这个扩展案例非常适合练习“同一逻辑迁移到不同场景”。如果能把多个文件合并、同文件多 sheet 合并都理解清楚后续处理月报、季度报、分部报表会轻松很多。9. 总结提升合并不是复制合并是规则化处理这一篇的核心不是简单记住all_data all_data values而是理解批量合并背后的自动化思维。多个工作簿中的同名工作表本质上是多个结构相似的数据源汇总工作簿则是统一输出结果。本文最关键的判断有三点第一目标工作表是否存在第二是否第一次读取表头第三读取到的数据是否有效。只要这三点处理好脚本的稳定性就会明显提高。真正可复用的脚本不是只会在一次练习文件上跑通而是能处理异常、能跳过无效文件、能输出清晰结果。这才是办公自动化和简单代码练习之间的区别。最后提醒一句批量合并前一定要备份源文件并用少量样本先测试。尤其是涉及财务、库存、资产、人事等数据时脚本跑得快不是优点跑得稳、结果可验证才是优点。 返回顶部点击回到顶部