查看: 134|回复: 3

Python + xlwings 按分类字段拆分 Excel 总表为多个工作簿的实战脚本

[复制链接]
发表于 2 小时前 | 显示全部楼层 |阅读模式
在日常办公中,经常需要将一张包含多类数据的 Excel 总表,按照某个字段(如产品、地区、门店)拆分成多个独立的工作簿。如果手动操作,需要反复筛选、复制、新建、粘贴、保存,不仅效率低下,还容易出错。使用 Python 脚本可以一键完成这一任务,稳定且可复用。本文将基于 xlwings 库,详细讲解如何实现按条件拆分的完整流程,并提供可直接运行的代码。

## 一、业务场景与核心理念

典型场景包括:销售总表按产品拆分给产品负责人,门店数据按门店拆分给店长,区域业绩按地区拆分给区域经理。只要表格中有明确的分类列(如“类别”、“地区”等),就可以用程序自动分组输出。

核心思路是使用 Python 的字典(dict)作为“分类容器”。字典的键(key)是分类字段的值,值(value)是该分类下的所有数据行(列表形式)。例如:
  1. data = {
  2.   "背包": [
  3.     ["双肩包", "背包", 10, 129, 1290],
  4.     ["登山包", "背包", 5, 199, 995]
  5.   ],
  6.   "行李箱": [
  7.     ["拉杆箱", "行李箱", 8, 299, 2392]
  8.   ]
  9. }
复制代码

然后遍历字典,对每个 key 生成一个独立的工作簿,将表头和数据行写入后保存。这样,分类字段的值就直接决定了输出文件名和内容。

## 二、完整代码:按指定列拆分总表

以下代码使用 xlwings(操作 Excel 的第三方库),读取源文件,按指定列(默认第 1 列,即 B 列)分组,并输出到目标文件夹。代码已处理文件名非法字符、空分类值、工作表名称长度限制等问题。
  1. import os
  2. import re
  3. import xlwings as xw
  4. def safe_filename(name):
  5.     """将分类值转换为合法文件名,替换非法字符为下划线"""
  6.     name = str(name).strip()
  7.     name = re.sub(r'[\\/:*?"<>|]', "_", name)
  8.     return name if name else "未分类"
  9. # ====== 需要根据实际情况修改的参数 ======
  10. source_file = r"e:\file\总表.xlsx"
  11. source_sheet = "Sheet1"
  12. output_dir = r"e:\file\拆分结果"
  13. group_col_index = 1  # 按哪一列拆分:0 表示 A 列,1 表示 B 列,以此类推
  14. # =====================================
  15. os.makedirs(output_dir, exist_ok=True)
  16. app = xw.App(visible=False, add_book=False)
  17. try:
  18.     wb = app.books.open(source_file)
  19.     sht = wb.sheets[source_sheet]
  20.     # 读取连续区域(包含表头)
  21.     table = sht.range("A1").expand("table").value
  22.     if not table or len(table) < 2:
  23.         raise ValueError("源表数据为空或只有表头,没有可拆分的数据行。")
  24.     header = table[0]
  25.     rows = table[1:]
  26.    
  27.     data = dict()
  28.     for row in rows:
  29.         key = row[group_col_index]
  30.         if key is None or str(key).strip() == "":
  31.             key = "未分类"
  32.         key = str(key).strip()
  33.         if key not in data:
  34.             data[key] = []
  35.         data[key].append(row)
  36.    
  37.     for key, value in data.items():
  38.         file_name = safe_filename(key) + ".xlsx"
  39.         out_path = os.path.join(output_dir, file_name)
  40.         new_wb = app.books.add()
  41.         new_sht = new_wb.sheets[0]
  42.         new_sht.name = safe_filename(key)[:31]  # Excel 工作表名最长 31 字符
  43.         new_sht.range("A1").value = [header] + value  # 表头 + 数据行
  44.         new_wb.save(out_path)
  45.         new_wb.close()
  46.         print(f"已生成:{out_path},行数:{len(value)}")
  47.     wb.close()
  48. finally:
  49.     app.quit()
复制代码

## 三、关键代码解析

- **data = dict()**:创建一个空字典,用于存放分组结果。
- **if key not in data: data[key] = []**:如果该分类尚未出现,则初始化空列表。
- **data[key].append(row)**:将当前行追加到对应分类列表。
- **[header] + value**:将表头与数据行拼接,确保输出文件包含字段名称。
- **safe_filename(key)**:去除分类值中的空格,并将 Windows 非法字符(\ / : * ? " < > |)替换为下划线,避免保存失败。
- **new_sht.name = safe_filename(key)[:31]**:Excel 工作表名称长度不能超过 31 个字符,截断处理。

## 四、常见问题与检查要点

1. **分类字段为空**:脚本中已将 None 或空白行归入“未分类”,但实际业务中可能需要特殊处理(如跳过或报错)。
2. **分类值存在前后空格**:使用 strip() 去除空格,否则“华北”和“华北 ”会被视为两个不同分类。
3. **文件名重复冲突**:若多个分类清洗后得到相同文件名,后生成的会覆盖先前的。建议使用唯一编号避免覆盖:
  1. def get_unique_path(folder, filename):
  2.     base, ext = os.path.splitext(filename)
  3.     path = os.path.join(folder, filename)
  4.     index = 1
  5.     while os.path.exists(path):
  6.         path = os.path.join(folder, f"{base}_{index}{ext}")
  7.         index += 1
  8.     return path
复制代码

4. **输出目录不存在**:使用 os.makedirs(output_dir, exist_ok=True) 自动创建。

## 五、结果验证:确保拆分正确

运行脚本后,不能只看控制台无报错。应检查以下三点:
- 输出文件数量是否等于分类数量。
- 每个工作簿中的分类列数据是否一致(抽样检查)。
- 输出数据行总数是否等于源表数据行数。

可以使用以下代码快速核对:
  1. total_output_rows = 0
  2. for key, value in data.items():
  3.     print(f"{key}:{len(value)} 行")
  4.     total_output_rows += len(value)
  5. print(f"源数据行数:{len(rows)}")
  6. print(f"输出数据行数合计:{total_output_rows}")
复制代码

原理:按条件拆分且不删除数据,输出行数总和应等于源表数据行数。若不一致,需排查空值处理、过滤逻辑或数据读取范围。

## 六、实战总结

本文展示的“读取→分组→逐组输出”模型,可广泛应用于销售数据分发、资产清单拆分、人员绩效报表等场景。关键是先确认分类字段的可靠性,在输出前做数据清洗(去空格、处理空值、文件名合法化),最后对结果进行核对。将此脚本进一步封装,可加入图形界面或配置参数,成为稳定的办公自动化工具。
回复

使用道具 举报

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

Re: Python + xlwings 按分类字段拆分 Excel 总表为多个工作簿的实战脚本

非常实用的脚本,感谢分享!处理 Excel 拆分这个需求确实很常见,手动操作费时又容易出错。代码里对非法字符、空分类值、工作表名称长度限制这些细节都考虑到了,很严谨。字典分组 + xlwings 直接操作 Excel 应用的思路也很清晰,不用依赖临时文件,保存路径可以灵活指定,直接就能拿到结果。另外,建议可以在拆分前加个校验,看看分类列索引是否超出数据范围,或者表头是否包含预期的字段名,能防一手源表结构变化。总之这套模板可以改成带界面或者命令行参数的小工具,日常办公会非常方便。
回复 支持 反对

使用道具 举报

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

Re: Python + xlwings 按分类字段拆分 Excel 总表为多个工作簿的实战脚本

感谢分享,非常实用的脚本!代码结构清晰,注释也很到位,特别是对文件名字符处理和Excel工作表长度限制的考虑很周全,直接拿来修改参数就能用,省去了手动反复操作的麻烦。我通常用pandas处理这类拆分,但xlwings这种方式能直接保留原格式和公式,更贴合实际办公场景。想请教一下,如果总表数据量非常大(比如几十万行),内存占用方面有什么需要注意的吗?或者有没有批量分页保存的建议?再次感谢!
回复 支持 反对

使用道具 举报

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

Re: Python + xlwings 按分类字段拆分 Excel 总表为多个工作簿的实战脚本

感谢分享!这个脚本非常实用,尤其是 `safe_filename` 和键判断那部分的边界处理,考虑得很周到。我平时也用 xlwings 处理 Excel,但没想过把字典的键值对设计成“分类容器”,这个思路很清晰。 有个小建议:如果原表数据量很大(比如超过几万行),循环里逐行 `data.append(row)` 可能稍慢,或许可以用 `pandas` 的 `groupby` 先分组再转列表,不过依赖库就多了。另外 `data = []` 那行有点笔误,应该是 `data = []` 吧? 总之代码可以直接复用,对办公自动化很友好。感谢分享!
回复 支持 反对

使用道具 举报

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

本版积分规则

指导单位

江苏省公安厅

江苏省通信管理局

浙江省台州刑侦支队

DEFCON GROUP 86025

Hacking Group 021A

旗下站点

态势感知中心

应急响应中心

红盟安全

联系我们

官方QQ群:112851260

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

官方核心成员

关注微信公众号

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

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

Powered by ihonker.com

Copyright © 2015-现在.

  • 返回顶部