2026-10-02 · 喵窝资源铺
按月导出的销售记录、每周一份的打卡表、不同同事各管一段的客户名单——攒了一堆 CSV 要合成一张总表时,两大痛点就来了:重复数据(同一个人出现在好几个文件里)和 Excel 导出的怪格式(打开看着正常,程序一读名字前面多了个看不见的 BOM)。这篇给一个 30 行、零依赖(只用标准库) 的脚本:整个文件夹的 CSV 一次合并、自动去重、空行自动跳过。本文代码实跑验证,真实输出见下。
不需要 pip 装任何东西。存为 csv_dedup.py,运行 python csv_dedup.py 数据文件夹 合并结果.csv 手机号(第三个参数是「按哪一列判重」,不填就按整行判重):
"""CSV 批量合并 + 去重。用法:python csv_dedup.py [输入目录] [输出csv] [关键列名]"""
import csv, sys, glob, os
src = sys.argv[1] if len(sys.argv) > 1 else "."
out = sys.argv[2] if len(sys.argv) > 2 else "merged.csv"
key = sys.argv[3] if len(sys.argv) > 3 else None # 关键列名;缺省=整行去重
files = sorted(glob.glob(os.path.join(src, "*.csv")))
rows, seen, dup, header = [], set(), 0, None
for f in files:
with open(f, encoding="utf-8-sig", newline="") as fh: # utf-8-sig 兜住 Excel 导出的 BOM
r = csv.reader(fh)
h = next(r, None)
if h is None: continue
if header is None: header = h
ki = h.index(key) if key and key in h else None
for row in r:
if not any(cell.strip() for cell in row): continue # 跳过全空行
sig = row[ki] if ki is not None else tuple(row)
if sig in seen:
dup += 1
continue
seen.add(sig)
rows.append(row)
with open(out, "w", encoding="utf-8-sig", newline="") as fh:
w = csv.writer(fh)
w.writerow(header)
w.writerows(rows)
print(f"读入 {len(files)} 个文件 -> 输出 {len(rows)} 行,去掉重复 {dup} 行 -> {out}")
我造了 3 个文件、共 8 条数据,故意埋了三种坑:文件内重复(张三在同一文件出现两次)、跨文件重复(李四两个文件都有)、「半重复」(张三在补录文件里部门从「销售」改成了「销售部」,整行比对根本发现不了是同一人)。按手机号判重跑一遍:
读入 3 个文件 -> 输出 6 行,去掉重复 3 行 -> merged.csv 姓名,手机号,部门 张三,13812345678,销售 李四,13987654321,技术 王五,13711112222,市场 赵六,13566667777,销售 小明,13322223333, 小元代订,13699998888,市场
逐条核对:8 行进 6 行出,去掉的 3 条正是埋的三个重复——包括部门写法不一致的那个「半重复」,因为按手机号判重不看其他列。空行没进表,BOM 没污染第一个姓名。幂等验证:再跑一遍还是 6 行——输出整体覆盖不是追加,不会越跑越多。
encoding="utf-8" 读,第一列的列名会变成看不见字符开头的「\ufeff姓名」,后续按列名找关键列直接找不到。utf-8-sig 会自动剥掉它,输出时也用它,Excel 双击打开不乱码。next(r, None) 兜住空表头、any(cell.strip()) 跳过空行,这两处不处理脚本会直接崩或产出脏行。这个脚本按「所有文件列名一致」写的。如果各文件列名不统一(一个叫「电话」一个叫「手机号」)、要按条件只合并部分文件、或者去重时想保留最新一条而不是第一条——逻辑要再包一层,可以直接找我们代写(见下)。
相关阅读:批量合并 Excel | 群接龙转 Excel | 批量重命名文件 | Python 自动化能帮你做什么