快递查询API

← 技术博客

用 Python 对接快递查询接口:requests 完整示例

2026-07-26 · 阅读约 7 分钟

项目是 Python 写的(Django、Flask、FastAPI 后台,或者纯脚本、定时任务), 想加一个快递查询接口其实只差一个 requests.post。 本文全部代码都能直接跑,带你走完:发第一个请求 → 解析统一状态码 → 批量查询 → 处理失败条目 → 加重试 → 判断是否签收。

一、准备工作

注册(邮箱即可,无需企业认证),到控制台生成一对密钥: pk_ 开头的 API Key 与 sk_ 开头的 Secret Key。 然后装好 requests:

pip install requests

不想先注册?首页的在线演示用公开测试密钥就能试跑一遍。

二、发起第一个请求

接口是 POST /v1/tracking/trace,认证放在请求头里: Authorization: Bearer API_KEY:SECRET_KEY,两段密钥用英文冒号拼接。

import os
import requests

API_URL = "https://api.kuaidichaxunapi.com/v1/tracking/trace"

# 密钥从环境变量读取,切勿写死在源码里
API_KEY = os.environ["KUAIDI_KEY"]        # pk_ 开头
SECRET_KEY = os.environ["KUAIDI_SECRET"]  # sk_ 开头

headers = {
    "Authorization": f"Bearer {API_KEY}:{SECRET_KEY}",
    "Content-Type": "application/json",
}

payload = {"items": [{"courierCode": "cainiao", "trackingNumber": "CGD0000123456"}]}

resp = requests.post(API_URL, headers=headers, json=payload, timeout=10)
resp.raise_for_status()
body = resp.json()

items 是数组,一次最多 10 个。用 requests 的 json= 参数会自动序列化并带上 JSON 的 Content-Type,比手动 json.dumps 省事。

三、解析返回:状态与轨迹

返回是统一信封:body["data"]["results"] 与查询顺序一一对应。 每条先看 success,成功再读 data

tiao = body["data"]["results"][0]

if tiao["success"]:
    d = tiao["data"]
    print(d["trackingNumber"], d["deliveryStatusText"])  # 例如:已签收
    print("是否签收:", d["isDelivered"])
    # progresses 最新在前,逐条打印轨迹
    for p in d["progresses"]:
        print(p["dateTime"], p["statusCode"], p["description"])
else:
    err = tiao["error"]
    print("查询失败:", err["code"], err["message"])

省心的地方在于 deliveryStatus归一后的状态码(共 12 种), 而 deliveryStatusText 已经是对应中文,可直接展示,无需自己写一张映射表。 轨迹里的每条 progresses[i]dateTimelocationstatusstatusCodedescription

四、批量查询与失败分支

把多个运单号塞进 items 一次查完。批量里某条失败不会让整个请求报错, 逐条判断 success,并根据错误码区分对待:

def chaxun(items):
    resp = requests.post(API_URL, headers=headers, json={"items": items}, timeout=10)
    resp.raise_for_status()
    return resp.json()

danhao = [
    {"courierCode": "cainiao", "trackingNumber": "CGD0000123456"},
    {"courierCode": "sf", "trackingNumber": "SF9900001234567"},
]

body = chaxun(danhao)
print("汇总:", body["data"]["summary"])  # total / successful / failed / billable

for tiao in body["data"]["results"]:
    if tiao["success"]:
        d = tiao["data"]
        print(d["trackingNumber"], "→", d["deliveryStatusText"])
    else:
        err = tiao["error"]
        code = err["code"]
        if code == "COURIER_PREPARING":
            print(err["trackingNumber"], "该快递查询开发中,本次不计费")
        elif code == "NOT_FOUND":
            print(err["trackingNumber"], "暂无轨迹,稍后重试")
        else:
            print(err["trackingNumber"], "失败:", code)

两个错误码值得记住:NOT_FOUND 表示单号有效但暂无轨迹(新单常见),会计费COURIER_PREPARING 表示该公司查询功能仍在开发中,这类请求不消耗额度summary.billable 会告诉你这批实际计费了几条。

五、加上重试(指数退避)

网络抖动或偶发 5xx,用指数退避重试最稳妥——等待时间按 1、2、4 秒递增,避免瞬间打爆服务端:

import time

def chaxun_retry(items, max_retries=3):
    for attempt in range(max_retries):
        try:
            resp = requests.post(API_URL, headers=headers,
                                 json={"items": items}, timeout=10)
            resp.raise_for_status()
            return resp.json()
        except requests.RequestException as e:
            if attempt == max_retries - 1:
                raise  # 重试用尽,抛出
            wait = 2 ** attempt   # 1s, 2s, 4s… 指数退避
            print(f"第 {attempt + 1} 次失败,{wait}s 后重试:", e)
            time.sleep(wait)

提示:4xx(如 401 密钥错误、400 参数缺失)重试也没用, raise_for_status() 会抛出,检查密钥和请求体即可;只对超时和 5xx 做退避。

六、判断「是否已签收」

做「待收货 / 已完成」分类时,用归一状态码判断最通用——不同快递公司的原始描述千差万别, 但终态都会归到 DELIVERED

def yi_qianshou(tiao):
    # 用归一后的状态码判断,跨快递公司通用
    return tiao["success"] and tiao["data"]["deliveryStatus"] == "DELIVERED"

# 等价写法:直接用布尔字段 isDelivered
def yi_qianshou2(tiao):
    return tiao["success"] and tiao["data"]["isDelivered"]

一旦某单 isDelivered 为真,它已到终态,就不必再查,能省下不少额度。

小结

  • 认证是一个头:Authorization: Bearer pk_xxx:sk_xxx,密钥放服务端环境变量。
  • 批量逐条判断 success;失败看 error.code,其中 COURIER_PREPARING 不计费。
  • 只对超时 / 5xx 做指数退避;4xx 直接查问题。
  • 签收判断认准 DELIVERED / isDelivered,终态即可停查。

完整字段与限制见接口文档,各家快递编码见快递公司页。 免费额度每月 10000 次,够绝大多数 Python 项目起步。