Skip to content

品牌怎么抓窜货?用 IP 归属地核验经销商下单地和收货地(Python 实现) ​

某家电品牌渠道总监半夜收到一封邮件:华东大区三个经销商,上个月订的货全发到了同一个华南仓库。价格体系眼看要崩——窜货商低价收、高价卖,正规经销商压着库存卖不动,投诉电话打爆了总部。这种事靠人工抽查订单根本查不完,一天几千单,翻到猴年马月。

窜货(串货)是品牌渠道管理的老大难,但有个细节很多人没注意:经销商在系统里下单,后端是留了 IP 的。下单 IP 的归属地、收货地址、以及这个经销商平时常用的下单城市,三个信息一对,异地窜货单基本藏不住。这篇文章用 Python 写一套自动核验脚本,批量把订单表跑一遍,输出嫌疑窜货清单。

一、窜货单在数据上长什么样 ​

正常的经销商订单:经销商在自家门店/办公室下单,IP 归属地 ≈ 收货地址所在省 ≈ 常用下单地,三者一致或同省。

窜货单的特征是「两头分开」:

  • A 类:A 省经销商下单,收货地址直接填 B 省(货到了别处才暴露);
  • B 类:A 省经销商下单,收货地址写 A 省,但下单 IP 归属地在 B 省——这是最阴的一种,货根本没进过 A 省仓库,直接从生产地或窜货商处发走;
  • C 类:一个 IP 短时间内给多个不同收货地址下单——典型的集中下单、分散发货。

三类里,B 类完全靠 IP 归属地才能发现,这就是核验脚本的核心价值。

二、方案设计 ​

  1. 订单表导 CSV:订单号、经销商编号、下单 IP、收货省/市、下单时间;
  2. 每个 IP 查归属地(调 https://ip9.com.cn/get?ip=xxx,免费版 60 次/分钟,批量必须限速 + 缓存);
  3. 三方比对:下单 IP 省份 vs 收货省份 vs 该经销商历史常用省份;
  4. 规则引擎出结果:
    • 同省或 IP 省份 ∈ 常用省份 → 放行;
    • IP 省份 ≠ 收货省 → 标 A 级嫌疑(B 类窜货);
    • 同一 IP 关联 ≥3 个不同收货省 → 标 B 级嫌疑(集中下单);
    • 经销商第一次在陌生省份下单 → 标提醒(可能是出差,别一上来就当成窜货)。
  5. 输出嫌疑清单 CSV + 汇总统计。

三、Python 实现 ​

python
import csv
import time
import requests
from collections import defaultdict

CACHE = {}
LAST_CALL = 0.0

def query_geo(ip):
    """查归属地,缓存 + 限速,免费版 60 次/分钟"""
    global LAST_CALL
    if ip in CACHE:
        return CACHE[ip]
    now = time.time()
    if now - LAST_CALL < 1.1:
        time.sleep(1.1 - (now - LAST_CALL))
    try:
        r = requests.get(f"https://ip9.com.cn/get?ip={ip}", timeout=5)
        d = r.json()
        LAST_CALL = time.time()
        if d.get("ret") != 200:
            return None
        CACHE[ip] = d["data"]
        return d["data"]
    except Exception:
        return None

def load_orders(path):
    with open(path, encoding="utf-8-sig") as f:
        return list(csv.DictReader(f))

def build_common_provs(orders):
    """每个经销商的历史常用省份(取出现次数最多的省份集合)"""
    dealer_provs = defaultdict(list)
    for o in orders:
        dealer_provs[o["dealer"]].append(o["receive_prov"])
    common = {}
    for dealer, provs in dealer_provs.items():
        cnt = defaultdict(int)
        for p in provs:
            cnt[p] += 1
        common[dealer] = {p for p, c in cnt.items() if c >= 2}
    return common

def main():
    orders = load_orders("orders.csv")
    common = build_common_provs(orders)

    ip_prov = {}          # IP -> 省份(查一次用多次)
    ip_to_provs = defaultdict(set)
    suspects = []
    stats = {"total": len(orders), "pass": 0, "A": 0, "B": 0, "remind": 0}

    for o in orders:
        ip = o["ip"]
        if ip not in ip_prov:
            geo = query_geo(ip)
            ip_prov[ip] = geo.get("prov") if geo else None
        prov = ip_prov[ip]
        if not prov:
            continue  # 非法 IP/查询失败,跳过
        ip_to_provs[ip].add(o["receive_prov"])

    # 第二遍:先算完同 IP 多省,再逐单定性
    for o in orders:
        prov = ip_prov.get(o["ip"])
        recv = o["receive_prov"]
        dealer = o["dealer"]
        if not prov:
            continue
        flag = None
        if prov != recv:
            flag = "A"          # 下单地 != 收货地:B 类窜货
        elif len(ip_to_provs[o["ip"]]) >= 3:
            flag = "B"          # 同 IP 多省收货:集中下单
        elif prov not in common.get(dealer, set()) and recv in common.get(dealer, set()):
            flag = "remind"     # 首次陌生省份下单,先提醒
        if flag:
            suspects.append({**o, "ip_prov": prov, "flag": flag})
            stats[flag] += 1
        else:
            stats["pass"] += 1

    with open("suspects.csv", "w", newline="", encoding="utf-8-sig") as f:
        w = csv.DictWriter(f, fieldnames=list(orders[0].keys()) + ["ip_prov", "flag"])
        w.writeheader()
        w.writerows(suspects)

    print(f"订单总数 {stats['total']},正常 {stats['pass']},A 级嫌疑 {stats['A']},"
          f"B 级嫌疑 {stats['B']},提醒 {stats['remind']}")
    print("嫌疑单已输出 suspects.csv")

if __name__ == "__main__":
    main()

订单 CSV 长这样就能跑:

order_id,dealer,ip,receive_prov,receive_city,time
O1001,SH001,114.91.4.12,上海,上海市,2026-09-20 10:00:00
O1002,SH001,106.11.88.5,广东,广州市,2026-09-20 11:12:00

注意脚本核验的是省份维度,跨省才算嫌疑,同城/同省不折腾——窜货的定义本来就是跨区域。命中缓存只查一次,几千单的订单表,实际调接口的次数远小于订单数,免费额度基本够用。

四、落地注意事项 ​

  • IP 证据是线索不是定罪:B 类单子里,经销商在展会出差下单、在总部开会下单都会误报。A 级嫌疑先人工复核,别直接停货,等窜货商连续踩中同一种模式再处理;
  • 常用地白名单要渐进式维护:跑两周后把误报过的经销商城市加进白名单,准确率会明显上升;
  • 组合信号更硬:IP 异地 + 下单价格异常(低于指导价)+ 收货地址为仓库/物流园,三个信号同时命中才触发停单,单个信号只记录;
  • 合规:只取 IP 归属地做销售渠道分析,属于正常经营用途,但仍建议在经销商协议里写明「系统可能记录操作 IP」,避免争议;数据只留聚合结果,不留全部明细。

总结 ​

窜货单的藏法再多,也绕不开一个事实:下单的人得用网络,网络的出口 IP 总是带着归属地。把「下单 IP 归属地、收货地、经销商常用地」三张表一对,A/B 两类窜货模式就现形了。上面脚本直接套:orders.csv 按格式导出,跑完拿到 suspects.csv,先人工复核再定策略。接口用免费版 https://ip9.com.cn/get?ip=xxx(60 次/分钟,批量场景记得限速 + 缓存),量大了再考虑 VIP。官网:https://www.ip9.com.cn