Python批量提取Excel工作簿中所有工作表的唯一值
1. 问题背景:为什么要批量提取所有工作表的唯一值
本文主题是 批量提取一个工作簿中所有工作表的唯一值。这个案例看起来像是“去重”,但在真实办公场景里,它经常对应一个很高频的需求:从多个 sheet 中整理出一份标准清单。
比如一个工作簿里有 1 月、2 月、3 月、4 月等多个销售表,每张表里都有“产品名称”这一列。现在我们不关心每一行销量,只想整理出这个工作簿里出现过哪些产品。手工做法通常是:逐个 sheet 复制产品列,粘贴到一张新表,再使用 Excel 的“删除重复项”。如果 sheet 很多、文件很大,这个过程既慢,也容易漏。
这张图展示了本文的核心目标:用 Python + Excel 自动化,从一个工作簿的所有工作表中提取唯一值,并输出为一份清单。

从这张图中我们可以看出,数据来源不是单个工作表,而是一个工作簿内的多个工作表。程序会从多个 sheet 中收集“产品名称”,经过汇总、去重后,生成右侧的“产品名称清单”。这就是本文最核心的自动化链路:多表扫描 → 列数据收集 → 去重 → 写入新工作簿。
原理说明:这类任务的本质不是“操作 Excel 界面”,而是把 Excel 表格看成结构化数据:工作簿是容器,工作表是数据块,目标列是字段,唯一值清单是最终输出。
2. 适用场景:什么时候适合用这个脚本
这个脚本最适合用于“多个工作表结构类似,并且都包含同一个目标列”的场景。比如每个月一张销售表,每个部门一张人员表,每个区域一张客户表,只要表头字段一致,就可以批量提取某一列的唯一值。
这张图展示了一个典型场景:多张月度销售表中都有产品名称,现在需要整理出一份产品名称清单。

从这张图中我们可以看出,1 月、2 月、3 月、4 月这些工作表中都存在重复产品名称,例如“背包”“水杯”“钱包”“耳机”等。最终我们并不需要重复记录,而是只需要一份去重后的产品清单。这种场景如果靠复制粘贴,操作步骤很机械;用 Python 处理,则可以一次性完成。
适合使用这个方法的场景包括:
1. 从多张销售表中提取产品名称清单;
2. 从多个部门表中提取员工姓名清单;
3. 从多个客户表中提取客户名称清单;
4. 从多个设备表中提取型号、城市、部门、资产类别等去重字段。
限制条件:如果每张工作表的表头名称不统一,例如有的叫“产品名称”,有的叫“商品名称”,有的叫“产品名”,脚本就需要额外做字段映射,否则会漏掉部分工作表。
推荐做法:正式运行前,先统一表头字段。如果业务表格确实来源混乱,也可以在代码里维护一个候选字段列表,例如 ["产品名称", "商品名称", "产品名"],逐个匹配。
3. 核心原理:set() 去重 + 纵向写入 Excel
这一节真正要理解的不是某一行代码,而是数据从“重复列表”变成“唯一值清单”的过程。脚本会先把所有工作表中的目标列数据收集到一个列表里,这个列表允许重复;然后用 set() 去掉重复值;最后再写入新的 Excel 工作簿。
这张图展示了本文的关键原理:左侧是含重复的原始数据,中间通过 set() 去重,右侧得到唯一值清单,并通过纵向写入方式输出到 Excel。

从这张图中我们可以看出,原始数据中“背包”“行李箱”等值可能出现多次,但经过 set() 后,每个值只保留一份。随后使用 insert(0, 表头) 在列表最前面加入表头,再用 options(transpose=True) 按列纵向写入 Excel。
原理说明:set 的特点是天然不允许重复元素,所以它非常适合做唯一值提取。但 set 去重后默认不保证原始顺序,因此如果希望输出结果更整齐,通常会再配合 sorted() 做排序。
values = ["背包", "行李箱", "背包", "钱包", "水杯", "行李箱"] unique_values = list(set(values)) unique_values = sorted(unique_values) unique_values.insert(0, "产品名称")
注意:如果你需要保留“第一次出现的顺序”,不要直接依赖 set()。可以使用 dict.fromkeys() 保留原始顺序。
values = ["背包", "行李箱", "背包", "钱包", "水杯", "行李箱"] unique_values = list(dict.fromkeys(values))
这两个写法没有绝对谁更好。set() 简单直接,适合只关心唯一值;dict.fromkeys() 更适合保留原始出现顺序。真实写脚本时,要根据业务结果选择。
4. 实现流程:遍历、收集、去重、写入
在写代码之前,先把流程拆开看。这个案例可以分成四步:遍历工作表、收集目标列、去重、写入新工作簿。只要这四步理解清楚,后面的代码就不难。
这张图展示了完整执行流程:从左侧多工作表开始,经过目标列收集和 set() 去重,最后写入新的工作簿。

从这张图中我们可以看出,脚本不是直接“删除重复项”,而是先把每张表的目标列值全部收集起来,再统一去重。这个顺序很重要:先完整收集,再统一处理,比边遍历边零散处理更清晰,也更方便排查问题。
推荐做法:第一次运行脚本时,建议先打印每张工作表是否命中目标列,以及提取到了多少个值。这样能快速发现表头不一致、空表、隐藏表等问题。
5. 完整代码:xlwings 批量提取唯一值
下面是一个完整可运行版本。这个版本会遍历源工作簿中的所有工作表,查找指定表头列,把该列非空值收集起来,去除重复后输出到新的 Excel 文件中。
import xlwings as xw
# ====== 需要根据实际情况修改的参数 ======
file_path = r"e:\file\销售数据.xlsx" # 源工作簿
target_col = "产品名称" # 要提取唯一值的列名
out_file = r"e:\file\产品名称清单.xlsx" # 输出文件
# =====================================
app = xw.App(visible=False, add_book=False)
try:
wb = app.books.open(file_path)
all_values = []
for sht in wb.sheets:
table = sht.range("A1").current_region.value
if not table or len(table) < 2:
print(f"跳过:{sht.name},没有可处理的数据")
continue
header = table[0]
rows = table[1:]
if target_col not in header:
print(f"跳过:{sht.name},未找到列:{target_col}")
continue
col_idx = header.index(target_col)
count = 0
for row in rows:
if col_idx >= len(row):
continue
value = row[col_idx]
if value is None or str(value).strip() == "":
continue
all_values.append(str(value).strip())
count += 1
print(f"已读取:{sht.name},提取 {count} 个值")
wb.close()
# 去重并排序
unique_values = sorted(list(set(all_values)))
# 插入表头
unique_values.insert(0, target_col)
# 写入新工作簿
out_wb = app.books.add()
out_sht = out_wb.sheets[0]
out_sht.name = "唯一值清单"
# 按列纵向写入
out_sht.range("A1").options(transpose=True).value = unique_values
out_sht.autofit()
out_wb.save(out_file)
out_wb.close()
print(f"清单生成完成:{out_file}")
print(f"唯一值数量:{len(unique_values) - 1}")
finally:
app.quit()
这段代码里最关键的是 all_values.append(str(value).strip())。我在这里做了两个处理:第一,把值转成字符串,避免不同类型混在一起;第二,使用 strip() 去掉前后空格,避免“背包”和“背包 ”被识别成两个不同值。
风险提醒:如果你的目标列里既有纯数字,又有文本编号,比如 001、1、1.0,直接转字符串可能会影响结果判断。遇到编号类字段时,要先确认 Excel 中的真实数据格式。
原理说明:out_sht.range("A1").options(transpose=True).value = unique_values 的作用是把 Python 列表纵向写入 Excel。如果不加 transpose=True,列表默认会横向写入一行,不符合清单类表格的阅读习惯。
6. 效果验证:清单生成不代表结果一定正确
脚本运行完成后,不要只看控制台是否提示成功。对唯一值提取任务来说,真正要验证的是:目标列是否全部扫描到了,空值是否正确排除,重复值是否真正去掉,输出清单数量是否符合预期。
我一般会从三个角度验证:
第一,检查每个 sheet 是否都被读取。控制台输出里应该能看到每张工作表的处理情况。如果某张表提示“未找到列”,就要回头看表头是否写错。
第二,检查唯一值数量。如果原数据里大概只有 20 个产品,结果输出了 200 个,那大概率是字段里有空格、错别字、编码差异或表头选错了。
第三,打开输出文件,确认清单是纵向排列,并且第一行有表头。如果表头缺失,后续别人拿到这个文件时会不知道这一列代表什么。
print(f"原始收集值数量:{len(all_values)}")
print(f"去重后唯一值数量:{len(unique_values) - 1}")
推荐做法:如果是正式交付文件,可以额外输出一份“处理日志”,记录每张工作表读取到多少条数据、是否存在目标列、最终唯一值数量是多少。这样后续别人质疑结果时,可以回溯。
7. 举一反三:唯一值后再做统计汇总
提取唯一值只是第一层能力。很多时候,业务真正要的不是“有哪些产品”,而是“每个产品的销量是多少”。这时就要从 set() 去重升级到 dict 统计。
这张图展示了进阶思路:先从多个工作表中提取产品名称,再用字典累计销量,最后输出产品销量汇总表。

从这张图中我们可以看出,set() 适合回答“有哪些”,而 dict 更适合回答“每个有多少”。如果只做唯一值清单,输出结果只有产品名称;如果继续做统计汇总,就可以得到“产品名称 + 累计销量”的报表。
下面是一个按“产品名称”累计“销量”的示例:
import xlwings as xw
file_path = r"e:\file\销售数据.xlsx"
col_product = "产品名称"
col_qty = "销量"
out_file = r"e:\file\产品销量汇总.xlsx"
app = xw.App(visible=False, add_book=False)
try:
wb = app.books.open(file_path)
stat = {}
for sht in wb.sheets:
table = sht.range("A1").current_region.value
if not table or len(table) < 2:
continue
header = table[0]
rows = table[1:]
if col_product not in header or col_qty not in header:
continue
idx_p = header.index(col_product)
idx_q = header.index(col_qty)
for row in rows:
if idx_p >= len(row) or idx_q >= len(row):
continue
product = row[idx_p]
qty = row[idx_q]
if product is None or str(product).strip() == "":
continue
product = str(product).strip()
if qty is None or qty == "":
qty = 0
qty = float(qty)
stat[product] = stat.get(product, 0) + qty
wb.close()
out_wb = app.books.add()
out_sht = out_wb.sheets[0]
out_sht.name = "产品销量汇总"
out_sht.range("A1").value = [["产品名称", "累计销量"]]
result = sorted(stat.items(), key=lambda x: x[0])
out_sht.range("A2").value = result
out_sht.autofit()
out_wb.save(out_file)
out_wb.close()
print(f"统计完成:{out_file}")
print(f"产品数量:{len(stat)}")
finally:
app.quit()
原理说明:stat.get(product, 0) + qty 是字典累计的常用写法。如果产品第一次出现,就从 0 开始累计;如果已经出现过,就在原有销量基础上继续加。
注意:统计金额、销量、数量这类字段时,一定要确认数据能转成数字。如果单元格里混入“无”“-”“N/A”等文本,float() 会报错,需要提前清洗。
8. 常见问题与踩坑记录
这个案例虽然代码不长,但真实使用时容易踩几个坑。第一个坑是表头不一致。脚本是按表头名称查找列索引的,如果表头写错,代码不会自动知道你想要哪一列。
坑 1:目标列不存在。如果某张工作表没有“产品名称”列,脚本会跳过。这个行为本身没问题,但你必须知道它跳过了哪些表。否则最后清单少数据,你还以为脚本正常完成了。
坑 2:空格导致重复。“背包”和“背包 ”肉眼看起来差不多,但程序会认为是两个不同值。所以读取时建议统一使用 strip()。
坑 3:set 去重后顺序变化。如果你希望结果按字母、拼音或原始顺序展示,不能只写 list(set(values))。可以使用 sorted() 排序,或者使用 dict.fromkeys() 保留首次出现顺序。
坑 4:隐藏工作表也会被遍历。如果工作簿中存在隐藏 sheet,for sht in wb.sheets 也可能遍历到。正式场景下要确认是否需要处理隐藏表。
for sht in wb.sheets:
print(sht.name)
推荐做法:处理正式文件前先复制一份测试文件,避免脚本写入异常影响原始数据。虽然本文主要是读取源文件、输出新文件,但养成备份习惯没有坏处。
9. 总结提升:把“唯一值提取”变成通用清单工具
这一节的核心,不是记住 set() 这个函数,而是掌握一种清单类自动化思路:从多个工作表中提取目标列,统一收集,去重处理,最后输出为标准清单。
这类脚本非常适合沉淀成通用工具。只要把源文件路径、目标列名、输出文件路径做成参数,就可以复用到产品清单、客户清单、部门清单、城市清单、设备型号清单等多个场景。
我认为这篇笔记最值得留下来的经验有三点。
第一,先明确目标列。脚本不是魔法,它只能按你指定的字段提取数据。字段选错,结果一定错。
第二,先清洗再去重。去重之前要处理空格、空值、类型差异,否则输出清单看似去重,实际仍然混乱。
第三,输出后必须验证。唯一值数量、表头、纵向写入格式、是否遗漏工作表,这些都要检查。自动化不是跑完就结束,而是要能交付、能复查、能复用。
从办公自动化学习路径看,这一节已经从“操作 Excel”进入了“整理数据结构”的阶段。后续如果继续扩展,可以把唯一值提取、分类统计、数据汇总、异常值检查组合起来,形成一个真正可用的 Excel 数据清洗工具箱。
以上就是Python批量提取Excel工作簿中所有工作表的唯一值的详细内容,更多关于Python提取Excel工作表唯一值的资料请关注脚本之家其它相关文章!
相关文章
Python使用coloredlogso库打造彩色日志的全攻略
想象一下,当你的服务突然报错时,在一堆灰色文本中快速定位到那个鲜红的ERROR信息,能节省多少排查时间?这就是coloredlogs库的价值所在,下面我们就来看看它的具体使用吧2026-02-02
Python实现滑动平均(Moving Average)的例子
今天小编就为大家分享一篇Python实现滑动平均(Moving Average)的例子,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧2019-08-08


最新评论