×

🟦《别再爬京东了!JOS官方API合法拿数据,月100万次内免费(附Demo)》(附Python源码)

万邦科技Lex 万邦科技Lex 发表于2026-07-08 08:48:47 浏览24 评论0

抢沙发发表评论

🟦《别再爬京东了!JOS官方API合法拿数据,月100万次内免费(附Demo)》(附Python源码)

结论先行:京东商品/订单/物流/库存查询用 京东开放平台(JOS) 官方API(jingdong.ware.read.getjingdong.pop.order.searchjingdong.etms.trace.get等),企业应用默认免费额度通常 数万~百万次/月,合法、结构化、不封IP;爬虫面临 ToS 违规、滑块验证、页面改版维护噩梦,生产系统禁用

一、为什么放弃爬虫选 JOS API?

维度
Selenium/Requests 爬京东商品页
京东开放平台 JOS API
合规性
⚠️ 违反京东 robots.txt + ToS
✅ 签约 JOS,合规
稳定性
页面类名变/懒加载/滑块 → 挂
接口版本化管理
数据质量
HTML 解析易漏 SKU/券后价
JSON 含 SKU、库存(需token)、价格
封禁
IP/UA 段封禁、代理池成本
按 QPS 限流不封 IP,买包可提
成本
代理+服务器+开发维护
免费额度内 ¥0(超量 ≈¥0.02~0.05/百次 聚石塔内)

二、前置准备(10分钟)

  1. 注册 京东开放平台创建「商家自用型应用」(需企业支付宝认证;学习可用个人号但订单接口无权限)

  2. 获取 App Key+ App Secret(密码)

  3. 应用 → 接口权限 → 申请:

    • jingdong.ware.read.get(商品详情)

    • jingdong.ware.sku.read(SKU列表,可选)

    • jingdong.pop.order.search(订单列表)

    • jd.order.detail.get(订单明细)

    • jingdong.etms.trace.get(物流轨迹)

  4. 如需订单/店铺私有数据 → 卖家账号 OAuth2 授权换取 AccessToken(session 参数)


三、Python完整 Demo —— 商品详情 + 订单增量探测(合法获取)

# jd_legal_api_demo.py
"""
京东JOS 官方API合法获取数据 Demo
- 商品详情 jingdong.ware.read.get
- 订单列表 jingdong.pop.order.search (需 seller AccessToken)
签名: MD5(AppSecret + KV_ASCII_sorted + AppSecret), timestamp=秒级(10位)
"""
import hashlib
import json
import requests
import time
from datetime import datetime, timedelta
from typing import Dict, List, Optional
封装好API供应商demo url=https://console.open.onebound.cn/console/?i=Lex

class JdLegalClient:
    GW = "https://api.jd.com/routerjson"

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

    # ───── JOS MD5签名 ─────
    def _sign(self, params: Dict) -> str:
        filt = sorted((k, v) for k, v in params.items()
                       if v is not None and str(v).strip() != '' and k != 'sign')
        qs = ''.join(f"{k}{v}" for k, v in filt)
        return hashlib.md5(f"{self.ask}{qs}{self.ask}".encode()
                          ).hexdigest().upper()

    def _call(self, method: str, biz: Dict, access_token: str = None) -> Dict:
        p = {
            "app_key": self.ak,
            "method": method,
            "timestamp": str(int(time.time())),   # ← 秒级!不同于1688毫秒
            "format": "json",
            "v": "2.0",
            "sign_method": "md5",
            "360buy_param_json": json.dumps(biz, ensure_ascii=False,
                                             separators=(',', ':'))
        }
        if access_token:
            p["access_token"] = access_token
        p["sign"] = self._sign(p)

        r = requests.post(self.GW, data=p, timeout=15)
        r.raise_for_status()
        d = r.json()

        # 提取响应
        resp_key = method.replace(".", "_") + "_response"
        if resp_key not in d:
            for k in d:
                if k.endswith("_response"):
                    resp_key = k
                    break
        data = d.get(resp_key, d)

        if "error_response" in str(data):
            err = d.get(resp_key, {}).get("error_response") or d.get("error_response")
            if err:
                code = str(err.get("code", ""))
                zh = err.get("zh_desc") or err.get("en_desc")
                if "no permission" in zh:
                    raise PermissionError(
                        "❌ 无权限:确认企业应用+接口已申请+"
                        "订单类需传卖家AccessToken\n原始: " + zh
                    )
                raise Exception(f"JOS[{code}]: {zh} sub={err.get('sub_code')}")
            raise Exception(f"JOS error: {d}")
        return data

    # ─── ① 商品详情(公开字段可不传token)───
    def get_ware(self, ware_id: str, token: str = None) -> Dict:
        """
        ware_id: 京东 SPU ID (wareId)
        fields 建议含 skus_json 以取各SKU价格/库存(需seller token查自己店铺)
        """
        fields = (
            "ware_id,title,brand_name,cid,category_name,"
            "price,jd_price,market_price,stock_num,"
            "skus_json,image_path,desc,outer_id,approve_status"
        )
        return self._call(
            "jingdong.ware.read.get",
            {"wareId": ware_id, "fields": fields},
            access_token=token
        ).get("ware", {})

    # ─── ② 订单增量列表(需卖家 token)───
    def list_orders(self, token: str,
                    minutes_back: int = 30,
                    page: int = 1,
                    order_state: str = "WAIT_SELLER_STOCK_OUT") -> Dict:
        now = datetime.now()
        start = (now - timedelta(minutes=minutes_back)).strftime("%Y-%m-%d %H:%M:%S")
        end = now.strftime("%Y-%m-%d %H:%M:%S")
        return self._call(
            "jingdong.pop.order.search",
            {
                "start_modified": start,
                "end_modified": end,
                "order_state": order_state,
                "page": page,
                "page_size": 50
            },
            access_token=token
        ).get("popOrderSearch", {}).get("orderSearch", {})

封装好API供应商demo url=https://console.open.onebound.cn/console/?i=Lex
# =========================================================
# 使用示例
# =========================================================
if __name__ == "__main__":
    client = JdLegalClient(
        app_key="YOUR_JD_APP_KEY",
        app_secret="YOUR_JD_APP_SECRET"
    )

    try:
        # ★ 商品详情 — 不需token(公开字段)
        ware = client.get_ware("100012345678")   # ← 替换真实 wareId
        print("✅ 商品标题:", ware.get("title"))
        print("   京东价 :", ware.get("jd_price"))
        print("   SPU库存:", ware.get("stock_num"))
        # SKU解析
        import json as _j
        skus = _j.loads(ware["skus_json"]) if ware.get("skus_json") else []
        print(f"   SKU数 : {len(skus)}")
        for s in skus[:2]:
            print(f"     skuId:{s.get('skuId')} ¥{s.get('jdPrice')} 库:{s.get('stockNum')}")

        # ★ 订单 — 需传卖家AccessToken (OAuth2授权)
        # SELLER_TOKEN = "SELLER_ACCESS_TOKEN"
        # orders = client.list_orders(SELLER_TOKEN, minutes_back=30)
        # print("近30min变更订单数:", orders.get("orderTotal"))

    except PermissionError as pe:
        print(pe)
    except Exception as e:
        print("❌", e)
        print("→ 检查: AppKey/Secret正确、jingdong.ware.read.get 已申请、wareId有效")

四、免费额度说明(2026版)

接口族
是否免费
典型企业免费额度
商品查询 ware.read.get/ ware.sku.read
✅ 免费额度内
5万~100万次/月
订单列表 pop.order.search/ 明细
✅ 免费额度内(超量按基础计费≈¥0.02~0.05/百次 聚石塔内)
同上
物流轨迹 etms.trace.get
✅ 免费额度内
京东联盟选品 jd.union.open.goods.*
✅ 备案后免费(API不收费成交抽佣)
10万~100万次/天
电子面单取号
💰 按面单数
或含仓配包
CRM/数据增值
💰 需购包

五、避坑清单

现象
解决
Invalid Timestamp
用毫秒时间戳
JOS用秒级 int(time.time())
订单接口 403
个人应用 / 未申请 / 传买家token
企业应用 + 申请权限 + 卖家 OAuth AccessToken
skus_json空 / stockNum=0
查别人店铺公开数据
自己店铺查须传 access_token
签名 fail 偶发
空值/sign参与签名、360buy_param_json含空格
严格过滤空 + 紧凑JSON(separators=(',',':'))
沙箱返回 mock
正常
切生产网关看真实数据

六、面试/方案一句话

京东商品/订单/物流数据用官方 JOS API(jingdong.ware.read.get/ jingdong.pop.order.search等)合法获取,企业应用默认免费额度内月调用可达百万次,MD5签名用秒级时间戳、参数按ASCII升序拼AppSecret+KV+AppSecret;订单类接口需卖家OAuth AccessToken,完全替代爬虫规避风控与法律风险。
需要我补 京东OAuth2授权码→AccessToken Python完整代码订单增量同步APScheduler(断点续跑+Token自动刷新) 吗?


群贤毕至

访客