← 返回文章列表 | 代做服务

从一堆Excel里批量提取手机号并去重

客户名单散落在几十个Excel里,手机号有的带横线(138-1234-5678)、有的带空格、有的是纯数字,还要混在备注里。手工整理到崩溃?下面这份脚本一次搞定:提取 → 清洗 → 校验 → 去重 → 统计来源次数。

核心脚本(实跑通过版)

import openpyxl, re, glob

# 负向断言:左右都不是数字,防止从长订单号里"截"出假手机号
PAT = re.compile(r'(? 出现次数
for p in sorted(glob.glob('客户表/*.xlsx')):
    wb = openpyxl.load_workbook(p, data_only=True)
    for ws in wb:                     # 每个sheet都要扫
        for row in ws.iter_rows(values_only=True):
            for cell in row:
                if cell is None: continue
                for m in PAT.findall(str(cell)):
                    n = norm(m)
                    if n: seen[n] = seen.get(n, 0) + 1

# 导出
out = openpyxl.Workbook(); ows = out.active
ows.append(["手机号", "出现次数"])
for k, c in seen.items(): ows.append([k, c])
out.save('手机号清单.xlsx')

实跑结果

测试数据:5行客户表(3种格式混用)+ 1个含13位长数字串的边角文件。

3个真坑(都是实跑撞出来的)

坑1:不带边界的正则会从长数字串里"截"出手机号

如果写成 1[3-9]\d{9} 直接 findall,遇到13位订单号 1238123456789 不会命中(第2位是2),但遇到 91381234567800 这类串就会从中间抠出 13812345678——把订单号的碎片当成客户号码群发短信,事故级别。必须加 (?。

坑2:横线/空格格式不先归一化,同一个号码会变成两条

138-1234-5678 和 13812345678 是同一个客户,但字符串不同。先 re.sub(r'\D','',s) 再校验长度与号段,去重才成立。校验放归一化之后,否则带横线的合法号码会被长度检查误杀。

坑3:忘了 data_only=True,公式格读出来的是公式本身

如果手机号是 =VLOOKUP(...) 拼出来的,不带 data_only=True 时 openpyxl 给你的是公式字符串——正则一个号码都提不到,还以为是正则写错了。参数加上后读的是上次Excel保存时的缓存值。

延伸

号码整理出来只是第一步:要不要按来源文件标注归属、要不要顺带保留客户姓名对应行,都是一行代码的扩展。需要按 姓名-手机号-备注 整表合并去重的,看这篇《多份Excel客户名单合并去重》。

懒得自己跑?把表格发给我们代做:提取/清洗/去重/合并都可以,看服务列表,¥9.9起。

本文所有代码均为实跑验证后发布,测试数据可复现。虚拟服务交付后不退款;未达承诺免费重做。