技术博客
手机归属地查询:电商风控,用归属地识别异常下单与区域分布

手机归属地查询:电商风控,用归属地识别异常下单与区域分布

作者: 万维易源
2026-08-27
手机归属地查询电商风控归属地比对异常下单
# 手机归属地查询:电商风控,用归属地识别异常下单与区域分布 > **接口**:手机归属地查询 `6-1` | **是否免费**:是(注册默认可免费调用,有使用档次限制)| **请求方式**:POST / GET | **返回格式**:JSON | **适用人群**:电商风控 / 运营 / 数据分析同学 | **阅读时间**:约 8 分钟 ## TL;DR - 把收货号码的归属地 `prov` / `provCode` 与用户填写的收货省份做一致性比对,不一致可作为异常下单的**辅助预警信号**。 - 按 `prov` 聚合订单,可以快速得到区域销量分布,辅助选品、仓配与投放决策。 - 这是**辅助风控信号,不是唯一判据**;接口免费、单参数、失败不扣点数,适合在用户侧脚本里循环调用(受免费档位限制)。 ## Why:为什么电商要用归属地 电商场景下,手机号是贯穿注册、下单、收货的核心标识。一个常见风险是:**用户填写的收货地址省份,和它绑定手机号的归属省份对不上**。比如收货地址写"广东",但号码号段归属在"云南",这种错位本身不代表欺诈,但值得进入人工复核或二次验证的队列——它可能是误填、代付、地址被篡改,也可能是更值得警惕的信号。 另一个高频需求是**区域销量分布**。运营和供应链团队往往想知道"这个月来自哪些省的订单最多"。与其维护一套地址解析规则,不如直接用号码归属地的 `prov` 字段做聚合:号码归属是标准化的省名,聚合逻辑简单、稳定。 需要强调的是,归属地只是**众多风控维度里的一个**,它不能证明"这是坏人",也不能替代设备指纹、支付验证、历史行为等成熟手段。本文把它定位为"低成本、可叠加的辅助信号"。 ## What:接入前准备与接口速览 前置条件: 1. 在 [易源官网](https://www.showapi.com) 注册账号(本接口为免费服务,注册默认可调用)。 2. 进入 [AppKey 管理页](https://www.showapi.com/console#/myApp) 复制 AppKey,后面代码替换 `YOUR_APPKEY`。 3. 准备好要查询的手机号(订单里的收货号码)。 | 项目 | 内容 | |------|------| | 接口名称 | 手机归属地查询 | | 接入点 | `6-1`(本接口仅 1 个接入点,同步请求-响应) | | 接口地址 | `https://route.showapi.com/6-1?appKey={your_appKey}` | | 请求方式 | POST 或 GET | | 必填参数 | `num`(手机号,字符串) | | 返回格式 | JSON,业务数据在 `showapi_res_body` | | 计费 | 免费服务(注册默认可免费调用,设使用档次限制);**失败不扣点数** | | 更新频率 | 半年更新一次新号段归属地 | | 注意 | **不支持携号转网查询** | ## How:从号码到风控信号 ### 步骤 1 · 写一个归属地查询函数 下面代码封装了一个查询函数,带 10s 超时和 `ret_code` 判断。失败时返回 `None`,不扣点数,可放心在批量比对前调用。 ```python import requests API_URL = "https://route.showapi.com/6-1" APP_KEY = "YOUR_APPKEY" # 替换为你的真实 AppKey def query_attribution(phone: str): """查询手机号归属地,失败返回 None(不扣点数)。""" try: resp = requests.get( API_URL, params={"appKey": APP_KEY, "num": phone}, timeout=10, ) data = resp.json() body = data.get("showapi_res_body", {}) if body.get("ret_code") == 0: return body # ret_code != 0 表示失败(如 -2 非11位、-4 格式错),不扣点数 return None except Exception: return None ``` ### 步骤 2 · 归属地与收货地址一致性比对 用返回的 `prov`(省名)或 `provCode`(省别编码)和订单里用户填写的收货省份做比对。不一致则打标为"待复核"。 ```python def check_address_consistency(phone: str, ship_prov: str) -> dict: """比对号码归属省份与收货填写省份。""" body = query_attribution(phone) if body is None: return {"match": None, "reason": "归属地查询失败/号码格式错"} phone_prov = body.get("prov") # 如 "云南" phone_prov_code = body.get("provCode") # 如 "530000" # 简单比对省名;生产环境建议同时用 provCode 做规范化比对 matched = (phone_prov == ship_prov) return { "phone_prov": phone_prov, "phone_prov_code": phone_prov_code, "ship_prov": ship_prov, "match": matched, "flag": "OK" if matched else "REVIEW", # 不一致进入复核队列 } # 示例:收货地址填广东,但号码归属云南 print(check_address_consistency("18908711111", "广东")) # -> {'phone_prov': '云南', 'ship_prov': '广东', 'match': False, 'flag': 'REVIEW'} ``` ### 步骤 3 · 按省份聚合区域销量分布 拿到一批订单的收货号码后,按 `prov` 聚合即可统计区域分布。 ```python from collections import Counter def region_distribution(orders: list) -> dict: """orders: [{ 'order_id':..., 'phone':... }];返回各省订单数。""" counter = Counter() for o in orders: body = query_attribution(o["phone"]) if body is None: counter["UNKNOWN"] += 1 continue counter[body.get("prov", "UNKNOWN")] += 1 return dict(counter.most_common()) orders = [ {"order_id": "A1", "phone": "18908711111"}, # 云南 {"order_id": "A2", "phone": "18908711111"}, # 云南 ] print(region_distribution(orders)) # -> {'云南': 2} ``` > 注意:上面的聚合是"用户侧脚本循环调用"的方式。免费档位有使用上限,订单量大时请先做客户端格式校验(11 位、纯数字),再考虑本地缓存手机号→归属地(详见系列缓存篇),避免浪费免费额度。 ## 返回示例与解析 ```json { "showapi_res_code": 0, "showapi_res_error": "", "showapi_res_id": "ce135f6739294c63be0c021b76b6fbff", "showapi_res_body": { "num": 1890871, "prov": "云南", "ret_code": 0, "areaCode": "0871", "name": "电信", "cityCode": "530100", "postCode": "650000", "provCode": "530000", "type": 2, "city": "昆明" } } ``` | 字段 | 含义 | 风控用途 | |------|------|----------| | `prov` | 省 | 与收货省份比对、区域聚合 | | `provCode` | 省别编码(本省身份证前几位) | 规范化省比对,减少"云南/云南省"写法差异 | | `city` | 市 | 更细粒度区域分布 | | `type` | 运营商枚举(1移动/2电信/3联通/4广电/-1未知) | 识别异常运营商组合(详见 type 篇) | | `num` | 号段(前 7 位) | 非完整号码,仅作号段参考 | | `ret_code` | 0 成功,其他失败 | 失败不扣点数 | > 字段完整含义见 [《手机归属地返回字段全解》](https://www.showapi.com/guides/phone-attribution-response-fields-6)。 ## 进阶 / 边界 - **辅助信号,不是判据**:归属地不一致只应进入"复核/二次验证"流程,不应直接拦截订单或封号。请配合支付验证、设备指纹等共同决策。 - **不支持携号转网**:号码携转后归属仍按原号段,可能和用户当前常住地不同,比对时要允许一定误报率。 - **失败不扣点数**:`ret_code != 0` 时不消耗额度,可放心在循环里对每个号码做格式前置校验。 - **免费档位限制**:循环调用受免费档位上限约束,量大时务必做客户端校验 + 本地缓存。 - **无经纬度**:接口不返回坐标,区域热力图需要外部地理编码。 ## FAQ **Q1:归属地不一致就一定是欺诈吗?** 不是。它只是异常信号之一,可能是误填、代付或携号转网导致。应作为"建议复核"而非"直接拦截"的依据。 **Q2:用 `prov` 还是 `provCode` 比对更好?** 建议优先用 `provCode`(数字编码)做规范化比对,避免"云南"与"云南省"等文字写法差异导致误判;`prov` 适合给人看。 **Q3:上千条订单循环调用会超免费额度吗?** 会。免费服务有使用档次限制。请先做 11 位/纯数字客户端校验,再对通过校验的号码查询,并缓存"号码→归属地"结果复用。 **Q4:`type` 字段在风控里怎么用?** `type` 标识运营商(1移动/2电信/3联通/4广电/-1未知)。它本身不是风险指标,但异常组合(如大量 `-1` 未知)可进入观察队列。详见 [《type 字段全解》](https://www.showapi.com/guides/phone-attribution-type-field-6)。 **Q5:能直接查一个号段的全部归属地做批量吗?** ShowAPI 没有官方批量查询能力。批量只能由你在用户侧脚本里循环单条调用,且受免费档位限制。 **Q6:返回的 `num` 是完整手机号吗?能用来匹配订单吗?** 不是。`num` 是号段(前 7 位),不是完整号码,不能用它做订单与用户的精确匹配,请用你系统里的完整号码。 ## 相关能力 / 下一步阅读 - [《手机归属地返回字段全解:prov/city/type/postCode 一文读懂》](https://www.showapi.com/guides/phone-attribution-response-fields-6) —— 每个字段类型、取值与坑位 - [《type 字段全解:1移动/2电信/3联通/4广电/-1未知怎么用》](https://www.showapi.com/guides/phone-attribution-type-field-6) —— 运营商枚举的实战用法 - [《物流/外卖场景:收货号码归属地校验与派送分区》](https://www.showapi.com/guides/phone-attribution-logistics-6) —— 把归属地用于派送分区与时效 - **本系列共 12 篇**:查看[手机归属地查询 · 官方指南总目录](https://www.showapi.com/guides/phone-attribution-guides-6)