手机归属地查询:按 cityCode 给收货号码匹配派送区域

约 13 分钟 进阶手机号码归属地查询物流派送cityCode 匹配区域路由
# 手机归属地查询:按 cityCode 给收货号码匹配派送区域 接口:手机归属地查询(apiCode=6,接入点 6-1)|是否免费:是,注册后默认可调用,设使用档次限制|请求方式:POST / GET|返回格式:JSON|适用人群:做物流调度、外卖派单、配送区域规划的开发者|阅读时间:约 8 分钟|最后实测核对:2026-09-18 配送站的路由表通常按行政区划代码组织,而手机归属地返回的 `cityCode` 正好是同一套编码体系。把收货号码的 `cityCode` 拿去匹配站点的服务范围,比用城市名字符串比对省事。这篇给出匹配逻辑、号码与地址的一致性检查,以及批量场景下的调用节奏。 ## 核心要点 - `cityCode` 是城市编码,实测北京返回 `110100`,适合直接和服务范围配置比对。 - `city` 是文字,同一城市有多种写法,做路由判断用 `cityCode` 更稳。 - 归属地粒度到市一级,物流分区的末端按站点自己的服务范围划分,不依赖接口。 ## 为什么用 cityCode 而不是城市名 `city` 返回的是城市名称文字。用文字做路由匹配会遇到几种麻烦:配置表里写「北京」,返回的是「北京市」;配置表用拼音缩写「bj」,对不上;同一城市在数据里出现多种写法。 `cityCode` 是数字编码,文档口径是「城市编码编码,本城市身份证的前几位编码」。实测 `13800138000` 落在北京时返回 `110100`,是稳定的 6 位编码。 | 实测输入 | 返回 `prov` / `city` | 返回 `cityCode` | |----------|----------------------|-----------------| | `13800138000` | 北京 / 北京 | 110100 | | `19200001234` | 广东 / 佛山 | 440600 | | `19700001234` | 青海 / 西宁 | 630100 | | `13800240000` | 辽宁 / 沈阳 | 210100 | 配送站的配置表按这套编码登记服务范围,比对就变成字符串前缀或编码相等判断,不用处理文字写法差异。 ## 查询与区域匹配 ```python import re import requests API_URL = "https://route.showapi.com/6-1" APP_KEY = "YOUR_APPKEY" # 正式环境从配置或密钥管理服务读取 # 配送站配置:cityCode 前缀 -> 站点 STATION_BY_CITY = { "1101": {"code": "BJ-01", "name": "北京一号站", "sla": "次日达"}, "4406": {"code": "FS-01", "name": "佛山一号站", "sla": "次日达"}, "6301": {"code": "XN-01", "name": "西宁一号站", "sla": "隔日达"}, "2101": {"code": "SY-01", "name": "沈阳一号站", "sla": "次日达"}, } def to_segment(raw) -> str | None: cleaned = re.sub(r"[-\s]", "", str(raw or "").strip()) if not re.fullmatch(r"\d{7,}", cleaned) or cleaned[0] == "0": return None return cleaned[:7] def locate(seg: str) -> dict: resp = requests.get( API_URL, params={"appKey": APP_KEY, "num": seg}, timeout=10, # 对齐官方 x-read-timeout ) body = resp.json().get("showapi_res_body", {}) if body.get("ret_code") != 0: return {"ok": False, "ret_code": body.get("ret_code"), "remark": body.get("remark")} return { "ok": True, "prov": body.get("prov"), "city": body.get("city"), "city_code": body.get("cityCode"), "prov_code": body.get("provCode"), "carrier_type": body.get("type"), "seg": body.get("num"), } def route_station(phone: str) -> dict: seg = to_segment(phone) if not seg: return {"routed": False, "reason": "号码格式不合规"} loc = locate(seg) if not loc["ok"]: # 查不到归属地时不阻断派送,落到人工分拣队列 return {"routed": False, "reason": f"归属地查询失败 ret_code={loc['ret_code']}"} city_code = str(loc["city_code"] or "") station = STATION_BY_CITY.get(city_code[:4]) if not station: return {"routed": False, "reason": f"无匹配站点 cityCode={city_code}", "prov": loc["prov"], "city": loc["city"]} return {"routed": True, "station": station, "loc": loc} ``` 匹配失败时把订单送进人工分拣队列,不要丢弃。归属地查不到的号段(`ret_code` 为 `-1`、`-5`、`-6`)和未覆盖的城市都会走到这个分支。状态码清单见[错误码逐条对照](https://www.showapi.com/guides/phone-attribution-error-codes-6)。 ## 号码归属地与收货地址的一致性检查 收货号码的归属地和收货地址在多数情况下一致,不一致时值得给一个提示,让分拣人员多看一眼。 ```python def address_mismatch(loc: dict, receiver_city_code: str) -> bool: """收货号码归属城市与收货地址城市不一致时返回 True。""" phone_city = str(loc.get("city_code") or "") addr_city = str(receiver_city_code or "") if not phone_city or not addr_city: return False return phone_city != addr_city ``` 这个检查只做提示,不做拦截。异地发货、代收、跨城订单都会产生不一致,把不一致当异常处理会拦下正常单量。 ## 时效预估里的用法 时效预估表按城市配置,用 `cityCode` 作为键,比用城市名做键少一层字符串规整。预估结果受实际运输线路影响,接口返回的只是号码归属城市,不参与线路计算,所以时效仍以承运方数据为准。 配送站的区域匹配只能用到市级。同一个城市内不同城区的差异,由站点自己的服务范围配置承担。 ## 批量回调订单时的调用节奏 一批订单进来时,先取前 7 位去重再查。实测确认归属地结果只跟前 7 位号段有关,同一号段的订单共用一条结果。 ```python from collections import Counter segments = [s for s in (to_segment(p) for p in order_phones) if s] unique = sorted(set(segments)) print(f"订单 {len(order_phones)} 笔,不同号段 {len(unique)} 个,需要 {len(unique)} 次调用") print("号段分布前 5:", Counter(segments).most_common(5)) ``` 去重后的号段数决定调用次数,与订单数量不成正比。免费档位的每日调用量与并发上限见[免费接口与档位说明](https://www.showapi.com/free-api),从 L0 档 100 次/天、1 QPS 起。批量脚本的完整写法见[用 Python 给 Excel 号码表批量补归属地](https://www.showapi.com/guides/phone-attribution-excel-batch-6)。 ## 缓存让重复订单不再重新查 派送场景里同一收件人可能有多笔订单,短期内重复查询同一个号段很常见。缓存键取前 7 位号段,成功结果可以缓存较长时间,失败结果用短 TTL。实现见[按前 7 位号段做缓存](https://www.showapi.com/guides/phone-attribution-cache-6)。 ## FAQ **Q1:`cityCode` 和收货地址的城市编码是同一套吗?** 同一套编码体系。文档口径是「本城市身份证的前几位编码」,实测北京返回 `110100`,与服务范围配置里的行政区划编码可以直接比对。 **Q2:为什么不用 `city` 字符串做路由?** 城市名称有多种写法,配置表和返回值的文字不一致会导致匹配失败。`cityCode` 是数字编码,没有这个问题。 **Q3:归属地能精确到区县吗?** 不能。返回粒度是省和市两级,实测最细到市。同一城市内不同城区的分区由配送站自己的服务范围配置承担。 **Q4:收货号码归属地和收货地址不一致要拦单吗?** 不建议拦。异地发货、代收、跨城订单都会不一致。可以做成提示让分拣人员多看一眼,不要做成拦截条件。 **Q5:归属地查不到的订单怎么办?** 送进人工分拣队列。`ret_code` 为 `-1`、`-5`、`-6` 时拿不到城市编码,无法自动匹配站点。失败时 `showapi_fee_num` 为 0,不消耗额度。 **Q6:一批订单要调多少次接口?** 按不同号段数计算。实测归属地结果只跟前 7 位号段有关,去重后的号段数就是需要调用的次数。 ## 下一步阅读 - [手机归属地查询返回 -2、-3、-4 是什么意思?错误码逐条对照与排查](https://www.showapi.com/guides/phone-attribution-error-codes-6) —— 匹配失败时的状态码含义 - [手机归属地查询按前 7 位号段做缓存:实测粒度与 Redis 实现](https://www.showapi.com/guides/phone-attribution-cache-6) —— 重复收件人的请求复用 - [手机归属地查询在电商风控里能做什么:可用维度与不成立的用法](https://www.showapi.com/guides/phone-attribution-ecommerce-6) —— 地域一致性的另一种用法 - **本系列共 12 篇**:查看[手机归属地查询指南总目录](https://www.showapi.com/guides/phone-attribution-guides-6)
加载中...