×

1688物流跟踪API:实时查询快递轨迹对接方案(附python源码) 🚚 1688物流跟踪API:实时查询快递轨迹对接方案(附Python源码)

万邦科技Lex 万邦科技Lex 发表于2026-06-12 15:46:54 浏览18 评论0

抢沙发发表评论

1688的物流跟踪主要通过两个接口完成:① 查询订单发货物流信息alibaba.logistics.trade.ship/ alibaba.logistics.order.get)和 ② 订阅/解析运单轨迹alibaba.logistics.trace.get)。对于ERP/WMS系统,核心目标是:拿到1688发货的运单号 → 定时拉取物流轨迹 → 回写ERP出库单状态


一、1688物流对接的两个核心接口

接口
用途
关键返回
alibaba.logistics.trade.ship
(或 alibaba.logistics.order.get
查某采购单的发货记录
logisticsCode(快递公司码)、billNo(运单号)、sendTime
alibaba.logistics.trace.get
根据companyCode+billNo实时轨迹
签收状态、节点时间、当前城市
⚠️ 前提:应用需申请物流查询权限(自用型应用默认可申请),订单须是已发货状态才有数据。

二、Python封装:查运单号 + 拉取轨迹

# ali1688_logistics.py
import hashlib
import time
import requests
import urllib.parse
from typing import Dict, List, Optional
from datetime import datetime, timedelta
# 封装好API供应商demo url=https://console.open.onebound.cn/console/?i=Lex
class Ali1688LogisticsClient:
    """
    1688 物流跟踪 Client
    网关与签名规则同标准1688 Open API
    """
    GATEWAY = "https://gw.open.1688.com/openapi/http/2/1"

    def __init__(self, app_key: str, app_secret: str, access_token: str):
        self.app_key = app_key
        self.app_secret = app_secret
        self.access_token = access_token

    # ─────────────── 签名(MD5) ───────────────
    def _sign(self, params: Dict) -> str:
        filtered = sorted((k, v) for k, v in params.items() if v is not None)
        qs = ''.join(f"{k}{v}" for k, v in filtered)
        raw = f"{self.app_secret}{qs}{self.app_secret}"
        return hashlib.md5(raw.encode('utf-8')).hexdigest().upper()

    def _call(self, method: str, biz: Dict) -> Dict:
        api_params = {
            "method": method,
            "app_key": self.app_key,
            "session": self.access_token,
            "timestamp": str(int(time.time() * 1000)),
            "format": "json",
            "v": "2.0",
            "sign_method": "md5",
        }
        api_params["param2"] = urllib.parse.quote_plus(
            str(biz).replace("'", '"')
        )
        api_params["sign"] = self._sign(api_params)

        resp = requests.get(self.GATEWAY, params=api_params, timeout=15)
        resp.raise_for_status()
        data = resp.json()

        if "error_response" in data:
            err = data["error_response"]
            raise Exception(f"1688 Logistics Err[{err.get('code')}]: {err.get('msg')}")

        result_key = [k for k in data if k != "error_response"][0]
        return data[result_key]

    # ─────────────── ① 查订单发货物流 ───────────────
    def get_order_logistics(self, order_id: str) -> List[Dict]:
        """
        返回该订单下所有物流单
        每个元素含: logisticsCode(快递码), billNo(运单号), companyName
        """
        biz = {"orderId": order_id}
        res = self._call("alibaba.logistics.trade.ship", biz)
        orders = res.get("logisticsOrders", []) or []
        result = []
        for lo in orders:
            result.append({
                "logistics_code": lo.get("logisticsCode"),     # 如 "YTO" "SF"
                "logistics_name": lo.get("logisticsCompanyName"),
                "bill_no": lo.get("billNo") or lo.get("mailNo"),
                "send_time": lo.get("gmtSend"),
                "consignee": lo.get("consigneeName")
            })
        return result

    # ─────────────── ② 查运单轨迹 ───────────────
    def get_trace(self, company_code: str, bill_no: str) -> Dict:
        """
        company_code: 1688返回的 logisticsCode (YTO/ZJS/SF...)
        bill_no: 运单号
        返回含 signStatus(已签/未签) + traceList
        """
        biz = {
            "companyCode": company_code,
            "billNo": bill_no
        }
        res = self._call("alibaba.logistics.trace.get", biz)
        return {
            "sign_status": res.get("signStatus"),      # SIGN 已签 / UNSIGN 未签
            "sign_time": res.get("signTime"),
            "traces": res.get("traceList") or []
        }


# =========================================================
# 使用示例:同步1688采购单物流 → 回写ERP
# =========================================================
if __name__ == "__main__":
    client = Ali1688LogisticsClient(
        app_key="YOUR_APP_KEY",
        app_secret="YOUR_APP_SECRET",
        access_token="YOUR_ACCESS_TOKEN"
    )

    ORDER_ID = "2338123456789000"   # 1688采购单号

    try:
        # ① 获取运单
        logistics = client.get_order_logistics(ORDER_ID)
        if not logistics:
            print("⚠️  该订单尚未发货或无物流信息")
            exit()

        for lg in logistics:
            print(f"\n📦 {lg['logistics_name']} 运单:{lg['bill_no']}")

            # ② 查轨迹
            trace = client.get_trace(lg["logistics_code"], lg["bill_no"])
            print(f"   签收状态: {trace['sign_status']}  {trace['sign_time'] or ''}")

            for node in (trace["traces"] or []):
                print(f"   [{node.get('time')}] {node.get('desc')} {node.get('city','')}")

            # ③ ERP联动(伪代码)
            # if trace['sign_status'] == 'SIGN':
            #     erp.mark_received(ORDER_ID, sign_time=trace['sign_time'])

    except Exception as e:
        print(f"❌ {e}")

三、1688快递公司码(LogisticsCode)常见值

快递
logisticsCode
说明
圆通
YTO
最常用
申通
STO
中通
ZTO
韵达
YD
顺丰
SF
需买家寄付/月结
京东
JD
邮政EMS
EMS
💡 避坑:1688返回的 logisticsCode是平台内部简码,直接传给 trace.get即可,不要自己映射汉字

四、ERP侧同步策略建议

┌──────────────┐   每30分钟轮询已发货未签收订单
│ 1688 已发货单│ ──────────────────────────────▶
└──────────────┘          │
                     get_order_logistics()
                     get_trace()
                          │
              ┌───────────▼──────────┐
              │  ERP出库单状态更新    │
              │  • 运输中 → 显示轨迹  │
              │  • SIGN → 标记已签收  │
              │  • 异常节点 → 告警   │
              └──────────────────────┘
  • 轮询频率:已发货未签收订单每30min查一次,签收后停止轮询

  • 失败重试:物流接口偶发超时,指数退避重试3次

  • 轨迹去重:按 (bill_no, time, desc)去重存储,避免重复写状态变更


五、高频避坑点

问题
原因
解决
返回空物流
订单未发货/waitsellersend状态
先判断订单status,仅查已发货
companyCode无效
自己手填汉字快递名
必须用1688返回的logisticsCode
轨迹长期不更新
快递公司未回传
正常,按sign_status判断是否最终签收即可
限流429
QPS过高
单应用 sleep≥0.2s 或令牌桶 QPS≤10

六、面试/方案一句话

1688物流对接 = 用采购单ID调 logistics.trade.ship拿运单号 → 调 logistics.trace.get拉轨迹 → 按 sign_status回写ERP签收状态,注意只对已发货订单查询且用平台返回的 logisticsCode
需要我把物流定时同步任务(APScheduler/Celery Beat)ERP签收回写SQL模板补给你吗?


群贤毕至

访客