查看: 100|回复: 3

Python xlwings批量提取Excel工作簿所有工作表唯一值:set去重与纵向写入

[复制链接]
发表于 2 小时前 | 显示全部楼层 |阅读模式
在日常办公中,经常需要从多个Excel工作表中整理出一份去重后的清单。例如一个工作簿包含1月到12月的销售表,每张表都有“产品名称”列,我们希望得到所有出现过的产品名称,而不关心具体销量。手动操作需要逐个复制、粘贴、删除重复项,效率低且容易出错。本文介绍用Python和xlwings库批量提取一个工作簿中所有工作表的唯一值,并输出为纵向排列的新工作簿。

适用场景:多个工作表结构类似且包含同一目标列,比如产品名称、员工姓名、客户名称、设备型号等。如果表头名称不统一,需要预先做字段映射或修改代码处理。

核心原理是遍历所有工作表,将目标列的每个值收集到一个列表中,然后用set()去重,最后将结果纵向写入Excel。set天然不含重复元素,但会打乱原始顺序;如果需要保留首次出现顺序,可以用dict.fromkeys()替代。去重后可以借助sorted()排序。

下面给出完整的批量提取唯一值代码。先修改file_path、target_col和out_file三个参数,分别指定源文件路径、目标列名和输出文件路径。
  1. import xlwings as xw
  2. file_path = r"e:\file\销售数据.xlsx"
  3. target_col = "产品名称"
  4. out_file = r"e:\file\产品名称清单.xlsx"
  5. app = xw.App(visible=False, add_book=False)
  6. try:
  7.     wb = app.books.open(file_path)
  8.     all_values = []
  9.     for sht in wb.sheets:
  10.         table = sht.range("A1").current_region.value
  11.         if not table or len(table) < 2:
  12.             print(f"跳过:{sht.name},没有可处理的数据")
  13.             continue
  14.         header = table[0]
  15.         rows = table[1:]
  16.         if target_col not in header:
  17.             print(f"跳过:{sht.name},未找到列:{target_col}")
  18.             continue
  19.         col_idx = header.index(target_col)
  20.         count = 0
  21.         for row in rows:
  22.             if col_idx >= len(row):
  23.                 continue
  24.             value = row[col_idx]
  25.             if value is None or str(value).strip() == "":
  26.                 continue
  27.             all_values.append(str(value).strip())
  28.             count += 1
  29.         print(f"已读取:{sht.name},提取 {count} 个值")
  30.     wb.close()
  31.     unique_values = sorted(list(set(all_values)))
  32.     unique_values.insert(0, target_col)
  33.     out_wb = app.books.add()
  34.     out_sht = out_wb.sheets[0]
  35.     out_sht.name = "唯一值清单"
  36.     out_sht.range("A1").options(transpose=True).value = unique_values
  37.     out_sht.autofit()
  38.     out_wb.save(out_file)
  39.     out_wb.close()
  40.     print(f"清单生成完成:{out_file}")
  41.     print(f"唯一值数量:{len(unique_values) - 1}")
  42. finally:
  43.     app.quit()
复制代码

代码中关键处理:将每个值转为字符串并strip()去除前后空格,避免“背包”和“背包 ”被视为不同值。如果目标列包含数字编号(如001和1),直接转字符串可能产生歧义,需根据实际数据格式调整。out_sht.range("A1").options(transpose=True).value = unique_values实现纵向写入,符合清单阅读习惯。

运行后不要只看成功提示,建议从三个方面验证:检查控制台输出是否每张表都被读取;对比唯一值数量是否合理;打开输出文件确认第一行有表头且数据纵向排列。

举一反三:如果需要统计每个产品累计销量,可将set升级为dict。下面是按“产品名称”累计“销量”的示例:
  1. import xlwings as xw
  2. file_path = r"e:\file\销售数据.xlsx"
  3. col_product = "产品名称"
  4. col_qty = "销量"
  5. out_file = r"e:\file\产品销量汇总.xlsx"
  6. app = xw.App(visible=False, add_book=False)
  7. try:
  8.     wb = app.books.open(file_path)
  9.     stat = {}
  10.     for sht in wb.sheets:
  11.         table = sht.range("A1").current_region.value
  12.         if not table or len(table) < 2:
  13.             continue
  14.         header = table[0]
  15.         rows = table[1:]
  16.         if col_product not in header or col_qty not in header:
  17.             continue
  18.         idx_p = header.index(col_product)
  19.         idx_q = header.index(col_qty)
  20.         for row in rows:
  21.             if idx_p >= len(row) or idx_q >= len(row):
  22.                 continue
  23.             product = row[idx_p]
  24.             qty = row[idx_q]
  25.             if product is None or str(product).strip() == "":
  26.                 continue
  27.             product = str(product).strip()
  28.             if qty is None or qty == "":
  29.                 qty = 0
  30.             qty = float(qty)
  31.             stat[product] = stat.get(product, 0) + qty
  32.     wb.close()
  33.     out_wb = app.books.add()
  34.     out_sht = out_wb.sheets[0]
  35.     out_sht.name = "产品销量汇总"
  36.     out_sht.range("A1").value = [["产品名称", "累计销量"]]
  37.     result = sorted(stat.items(), key=lambda x: x[0])
  38.     out_sht.range("A2").value = result
  39.     out_sht.autofit()
  40.     out_wb.save(out_file)
  41.     out_wb.close()
  42.     print(f"统计完成:{out_file}")
  43.     print(f"产品数量:{len(stat)}")
  44. finally:
  45.     app.quit()
复制代码

stat.get(product,0)+qty是字典累加常用写法。注意销量字段必须能转成数字,否则float()会报错,可提前清洗或异常处理。

常见问题:表头不一致导致部分sheet被跳过;空格导致去重失败;set去重后顺序变化;隐藏工作表会被遍历。正式运行前建议备份文件,先打印工作表名称确认范围。

总结:唯一值提取的本质是“遍历收集→去重→输出”,可以沉淀为通用工具。将源路径、目标列、输出路径参数化后,即可复用于产品、客户、部门、城市等多种清单生成。记住三个要点:先明确目标列、先清洗再去重、输出后必须验证。自动化不是跑完就结束,而是交付可复查的结果。
回复

使用道具 举报

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

Re: Python xlwings批量提取Excel工作簿所有工作表唯一值:set去重与纵向写入

感谢分享,写得非常详细!特别是用 `set` 去重后加表头纵向写入,逻辑很清晰。有个小问题想请教:如果工作表中数据量很大(比如几十万行),用 `current_region` 一次性读取整个区域会不会撑爆内存?有没有分块读取的替代方案?另外,用 `dict.fromkeys()` 保留首次出现顺序时,是否还能保持原来每个表的内部顺序?希望能进一步指点,谢谢!
回复 支持 反对

使用道具 举报

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

Re: Python xlwings批量提取Excel工作簿所有工作表唯一值:set去重与纵向写入

楼主的分享非常实用!用 `set()` 去重加 `sorted()` 排序的思路简洁高效,而且特意处理了空值和前后空格细节,考虑得很周到。特别是那个 `dict.fromkeys()` 保留顺序的小贴士,对于需要保持原始出现顺序的场景很有帮助。我已经把代码存下来准备用在日常的报表整理上了。 想请教一下:如果工作表中目标列包含合并单元格,或者某个单元格内有多行文本(比如用换行符分隔的多个产品名称),当前的逻辑是直接取单元格整体值,有没有好的办法拆分成多个条目后再去重呢?期待楼主的进一步指点。
回复 支持 反对

使用道具 举报

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

Re: Python xlwings批量提取Excel工作簿所有工作表唯一值:set去重与纵向写入

亲测有效,代码逻辑清晰,特别是 set 去重和纵向写入的写法很实用。之前手动搞月度汇总表时总是漏掉某个产品,这下可以一键统一整理了。有个小建议:如果目标列数据量特别大,可以考虑用 pandas 的 unique 替代 set,处理速度会更快一些。另外对数字编号那部分的提醒也很到位,确实字符串转换要注意格式一致性。感谢分享!
回复 支持 反对

使用道具 举报

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

本版积分规则

指导单位

江苏省公安厅

江苏省通信管理局

浙江省台州刑侦支队

DEFCON GROUP 86025

Hacking Group 021A

旗下站点

态势感知中心

应急响应中心

红盟安全

联系我们

官方QQ群:112851260

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

官方核心成员

关注微信公众号

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

GMT+8, 2026-7-1 12:04 , Processed in 0.040609 second(s), 17 queries , Gzip On, Redis On.

Powered by ihonker.com

Copyright © 2015-现在.

  • 返回顶部