全部
常见问题
产品动态
精选推荐

京东商品 SKU 信息接口(jingdong.ware.sku.get)技术干货:数据拉取、规格解析与字段治理(附踩坑总结 + 可运行代码

管理 管理 编辑 删除

京东商品 SKU 接口是获取商品规格、库存、价格等核心数据的关键技术入口 —— 和评论接口不同,SKU 数据更侧重 “结构化属性”,比如颜色 / 尺寸规格映射、不同 SKU 的库存差异、区域定价规则等,这些数据对库存同步、商品上架、价格监控至关重要。之前折腾京东接口时,光 SKU 的 “规格值编码映射” 就踩过不少坑(比如同一个 “红色” 在不同商品里编码不一样),后来整理了一套完整的技术方案。这篇纯技术视角拆解接口对接全流程,聚焦参数配置、签名生成、规格解析等核心环节,附上能直接跑的代码和自己踩过的坑,帮大家少走弯路。

一、接口核心技术参数与权限基础

1. 关键技术参数(必选 / 可选标注)

SKU 接口参数(https://o0b.cn/lin)对 “格式精度” 要求极高,比如 SKU ID 必须是纯数字,区域编码需匹配京东标准,任一参数错误会直接返回 “参数校验失败”


参数名类型说明是否必选技术约束
app_keyString应用唯一标识(从开放平台获取)长度 32 位,仅含字母数字,不可修改
app_secretString接口签名密钥需通过环境变量读取,禁止硬编码到代码或配置文件
methodString接口名称固定为 “jingdong.ware.sku.get”(旧接口 “jingdong.sku.get” 已停用)
sku_idStringSKU 唯一标识纯数字格式,长度 10-15 位(需与商品主 ID 匹配,否则返回 “SKU 不存在”)
timestampString请求时间戳格式 “YYYY-MM-DD HH:MM:SS”,与京东服务器时间差≤3 分钟,建议用 UTC+8 时间
formatString响应格式仅支持 “json”,不支持 xml,指定其他格式会返回 “不支持的响应类型”
vString接口版本稳定版本 “2.0”,低版本 “1.0” 会返回 “版本已废弃”
sign_methodString签名算法固定为 “md5”,无其他可选算法,填错会返回 “签名算法错误”
area_idString区域编码京东标准区域 ID(如北京为 110100),不填默认返回全国通用库存
fieldString需返回字段逗号分隔(如 “sku_id,stock,price”),不填返回全部字段,建议指定减少传输量

2. 权限申请技术要点

SKU 接口权限审核比评论接口更关注 “数据用途合规性”,需注意这几个技术细节:

  • 开发者认证:个人认证需提交身份证正反面 + 手持照,企业认证需额外提供营业执照(需与应用主体一致),避免因主体不匹配导致权限被拒;
  • 接口用途说明:需明确标注 “用于内部商品数据管理、库存同步”,避免出现 “商业爬取”“外部数据分发” 等违规表述,可附简单的技术架构图(如 “SKU 接口→数据存储→库存管理系统”);
  • 配额管理:个人开发者默认日调用限额 500 次,企业开发者 3000 次,若需更高配额,需提供 “业务量证明”(如店铺日订单量、商品 SKU 总数)。

二、核心技术实现:从签名到规格解析

1. 签名生成机制(SKU 接口专属坑点)

SKU 接口签名规则和评论接口一致,但需注意 “area_id 为空时的参数处理”—— 空值参数无需参与签名,否则会导致 “签名无效”,技术实现如下:


import hashlib
import sortedcontainers
def generate_sku_sign(params: dict, app_secret: str) -> str:
    """
    生成京东SKU接口签名(处理空值参数,避免签名错误)
    :param params: 待签名参数字典(不含sign字段)
    :param app_secret: 应用密钥
    :return: 32位大写签名字符串
    """
    # 坑点1:过滤空值参数(area_id等可选参数为空时不参与签名)
    valid_params = {k: v for k, v in params.items() if v is not None and str(v).strip() != ""}
    # 坑点2:按参数名ASCII码升序排序(用SortedDict确保排序稳定性)
    sorted_params = sortedcontainers.SortedDict(valid_params)
    # 坑点3:拼接格式为"keyvalue"(无分隔符),首尾必须加app_secret
    sign_str = app_secret
    for key, value in sorted_params.items():
        # 坑点4:参数值需转为字符串(数字型参数如area_id不转会导致签名偏差)
        sign_str += f"{key}{str(value)}"
    sign_str += app_secret
    # 坑点5:必须用UTF-8编码(含中文的field参数会导致加密错误)
    return hashlib.md5(sign_str.encode("utf-8")).hexdigest().upper()

2. 接口调用客户端(含规格解析)

SKU 接口核心技术难点是 “规格值编码映射”(如 “1627207:3232483” 对应 “颜色:红色”)和 “区域库存差异处理”,客户端实现如下:


import requests
import json
import time
import logging
from dataclasses import dataclass
from typing import List, Optional, Dict
# 日志配置(技术调试必备,记录详细错误信息)
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(module)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger("jd-sku-api")
# SKU数据模型(结构化存储,避免字段混乱)
@dataclass
class JdSkuModel:
    sku_id: str                # SKU唯一ID
    ware_id: str               # 商品主ID
    spec_text: str             # 规格描述(如“红色-XXL”)
    spec_code_map: Dict[str, str]  # 规格编码映射(如{"颜色":"3232483","尺寸":"12345"})
    stock: int                 # 库存数量
    price: float               # 销售价格
    original_price: float      # 原价
    area_id: str               # 区域编码
    status: str                # 状态(1-在售,0-下架)
    create_time: str           # 创建时间
class JdSkuAPIClient:
    def __init__(self, app_key: str, app_secret: str, timeout: tuple = (3, 10)):
        self.app_key = app_key
        self.app_secret = app_secret
        self.base_url = "京东开放平台SKU接口指定地址"  # 按平台文档配置,无硬编码链接
        self.timeout = timeout
        # 初始化长连接(减少TCP握手开销,提升并发性能)
        self.session = self._init_session()
    def _init_session(self) -> requests.Session:
        """初始化请求会话,配置连接池与重试机制"""
        session = requests.Session()
        adapter = requests.adapters.HTTPAdapter(
            pool_connections=10,
            pool_maxsize=50,
            # 重试策略:针对5xx错误自动重试3次,避免临时网络问题
            max_retries=requests.packages.urllib3.util.retry.Retry(
                total=3,
                status_forcelist=[500, 502, 503, 504],
                backoff_factor=0.5
            )
        )
        session.mount('https://', adapter)
        return session
    def _validate_params(self, params: dict) -> bool:
        """参数校验(SKU接口参数校验严格,需逐项检查)"""
        # 校验sku_id格式(纯数字)
        if not params.get("sku_id").isdigit():
            logger.error(f"SKU ID格式错误:{params.get('sku_id')}(需纯数字)")
            return False
        # 校验area_id(若传则为纯数字)
        area_id = params.get("area_id")
        if area_id is not None and not str(area_id).isdigit():
            logger.error(f"区域编码格式错误:{area_id}(需纯数字)")
            return False
        # 校验时间戳格式
        try:
            time.strptime(params.get("timestamp"), "%Y-%m-%d %H:%M:%S")
        except ValueError:
            logger.error(f"时间戳格式错误:{params.get('timestamp')}(需YYYY-MM-DD HH:MM:SS)")
            return False
        return True
    def get_sku_info(self, sku_id: str, area_id: Optional[str] = None, fields: Optional[List[str]] = None) -> dict:
        """
        核心方法:获取SKU详情数据
        :param sku_id: SKU唯一ID
        :param area_id: 区域编码(可选)
        :param fields: 需返回字段列表(可选)
        :return: 结构化结果(含成功状态、SKU数据)
        """
        # 1. 构建基础参数字典
        base_params = {
            "method": "jingdong.ware.sku.get",
            "app_key": self.app_key,
            "timestamp": time.strftime("%Y-%m-%d %H:%M:%S"),
            "format": "json",
            "v": "2.0",
            "sign_method": "md5",
            "sku_id": sku_id,
            "area_id": area_id,  # 可选参数,为空时自动过滤
            "field": ",".join(fields) if fields else None  # 字段筛选
        }
        # 2. 参数校验与签名生成
        if not self._validate_params(base_params):
            return {"success": False, "error": "参数格式校验失败"}
        base_params["sign"] = generate_sku_sign(base_params, self.app_secret)
        # 3. 发送请求(SKU接口仅支持POST,GET会返回405错误)
        try:
            response = self.session.post(
                url=self.base_url,
                data=base_params,  # 参数放data中,非params
                headers={"Content-Type": "application/x-www-form-urlencoded"},
                timeout=self.timeout
            )
            response.raise_for_status()  # 捕获4xx/5xx HTTP错误
            # 4. 解析响应数据
            try:
                result = json.loads(response.text)
            except json.JSONDecodeError as e:
                logger.error(f"JSON解析失败:{str(e)},响应片段:{response.text[:500]}")
                return {"success": False, "error": "响应数据格式异常"}
            # 5. 处理业务错误(京东错误码:0为成功)
            if result.get("code") != 0:
                error_msg = result.get("message", "未知业务错误")
                error_code = result.get("code", "未知错误码")
                logger.error(f"接口业务错误:{error_msg}(错误码:{error_code})")
                return {"success": False, "error": f"{error_msg}(错误码:{error_code})"}
            # 6. 结构化SKU数据(核心:解析规格编码映射)
            raw_sku = result.get("data", {}).get("sku", {})
            if not raw_sku:
                logger.error(f"未获取到SKU数据:sku_id={sku_id}")
                return {"success": False, "error": "未获取到SKU数据"}
            parsed_sku = self._parse_sku_data(raw_sku, area_id)
            return {
                "success": True,
                "sku_info": parsed_sku
            }
        except requests.exceptions.RequestException as e:
            logger.error(f"请求异常:{str(e)}")
            return {"success": False, "error": f"请求异常:{str(e)}"}
        except Exception as e:
            logger.error(f"未知处理异常:{str(e)}")
            return {"success": False, "error": f"未知处理异常:{str(e)}"}
    def _parse_sku_data(self, raw_sku: dict, area_id: Optional[str]) -> JdSkuModel:
        """
        解析SKU原始数据(核心技术点:规格编码映射与价格处理)
        :param raw_sku: 接口返回的原始SKU数据
        :param area_id: 区域编码(用于填充模型)
        :return: 结构化JdSkuModel
        """
        # 解析规格编码映射(如"spec_json":"{\"颜色\":\"3232483\",\"尺寸\":\"12345\"}")
        spec_code_map = {}
        spec_json = raw_sku.get("spec_json", "{}")
        try:
            spec_code_map = json.loads(spec_json)
        except json.JSONDecodeError:
            logger.warning(f"规格JSON解析失败:{spec_json},用空字典替代")
        # 解析规格描述(如"spec_text":"红色-XXL")
        spec_text = raw_sku.get("spec_text", "未知规格")
        # 价格处理(京东返回价格为分单位,需转为元)
        price = float(raw_sku.get("price", 0)) / 100.0
        original_price = float(raw_sku.get("original_price", 0)) / 100.0
        # 库存处理(部分商品返回"stock":"",需转为0)
        stock_str = raw_sku.get("stock", "0")
        stock = int(stock_str) if stock_str.isdigit() else 0
        return JdSkuModel(
            sku_id=str(raw_sku.get("sku_id", "")),
            ware_id=str(raw_sku.get("ware_id", "")),
            spec_text=spec_text,
            spec_code_map=spec_code_map,
            stock=stock,
            price=round(price, 2),
            original_price=round(original_price, 2),
            area_id=area_id or "",
            status="在售" if raw_sku.get("status") == 1 else "下架",
            create_time=raw_sku.get("create_time", "")
        )
# 使用示例(需替换为实际app_key与app_secret)
if __name__ == "__main__":
    client = JdSkuAPIClient(
        app_key="your_app_key",
        app_secret="your_app_secret"
    )
    # 获取SKU信息(指定区域为北京,仅返回核心字段)
    result = client.get_sku_info(
        sku_id="100012014970",
        area_id="110100",
        fields=["sku_id", "ware_id", "spec_text", "stock", "price"]
    )
    if result["success"]:
        sku = result["sku_info"]
        logger.info(f"SKU详情:{sku.sku_id} | 规格:{sku.spec_text} | 库存:{sku.stock} | 价格:{sku.price}")

三、高频技术坑与解决方案(个人踩坑总结)


技术问题错误表现解决方案(亲测有效)
签名无效(错误码 10003)接口返回 “签名无效”,空值参数参与签名1. 用字典推导式过滤空值参数({k:v for k,v in params.items() if v.strip()});2. 检查 area_id 为空时是否剔除;3. 确认 app_secret 与应用匹配
SKU 不存在(错误码 2001)接口返回 “SKU 不存在或无权限”1. 校验 sku_id 是否为纯数字(排除字母 / 特殊字符);2. 确认 SKU 所属商品未下架;3. 企业账号需检查是否有权限访问该商家 SKU
价格解析错误价格为 0 或异常大值(如 999999)1. 京东返回价格单位为 “分”,需除以 100 转为 “元”;2. 对空价格默认设为 0;3. 加价格范围校验(如if price > 10000: 记录异常)
规格 JSON 解析失败spec_json 字段为 “null” 或格式错误1. 用 try-except 捕获 JSONDecodeError;2. 失败时用空字典替代;3. 记录异常 SKU ID 便于后续排查
区域库存返回默认值无论传什么 area_id,库存都相同1. 确认 area_id 为京东标准区域编码(如上海 310100);2. 检查商品是否支持区域库存差异化(部分商品全国统一库存);3. 非自营商品需商家授权区域权限
调用超限(错误码 10004)接口返回 “调用频率超限”1. 实现令牌桶算法控制 QPS(个人≤2,企业≤5);2. 按 “sku_id + 时间戳” 做请求间隔(如同一 SKU5 秒内只查 1 次);3. 失败后延迟 3 秒重试,避免频繁请求

四、技术互动交流

以上内容是自己对接京东 SKU 接口时整理的技术方案,从签名生成到规格解析都踩过不少坑,代码里的每处注释基本都是遇到问题后补充的。如果大家在实际对接中遇到 “规格编码映射混乱”“区域库存不生效”“价格单位转换错误” 等技术问题,或者有关于 “高并发优化”“字段筛选技巧” 的疑问,欢迎在评论区留言 —— 技术问题不怕细,一起探讨解决方案,少走没必要的弯路~


请登录后查看

我是一只鱼 最后编辑于2025-09-29 11:58:48

快捷回复
回复
回复
回复({{post_count}}) {{!is_user ? '我的回复' :'全部回复'}}
排序 默认正序 回复倒序 点赞倒序

{{item.user_info.nickname ? item.user_info.nickname : item.user_name}} LV.{{ item.user_info.bbs_level || item.bbs_level }}

作者 管理员 企业

{{item.floor}}# 同步到gitee 已同步到gitee {{item.is_suggest == 1? '取消推荐': '推荐'}}
{{item.is_suggest == 1? '取消推荐': '推荐'}}
沙发 板凳 地板 {{item.floor}}#
{{item.user_info.title || '暂无简介'}}
附件

{{itemf.name}}

{{item.created_at}}  {{item.ip_address}}
打赏
已打赏¥{{item.reward_price}}
{{item.like_count}}
{{item.showReply ? '取消回复' : '回复'}}
删除
回复
回复

{{itemc.user_info.nickname}}

{{itemc.user_name}}

回复 {{itemc.comment_user_info.nickname}}

附件

{{itemf.name}}

{{itemc.created_at}}
打赏
已打赏¥{{itemc.reward_price}}
{{itemc.like_count}}
{{itemc.showReply ? '取消回复' : '回复'}}
删除
回复
回复
查看更多
打赏
已打赏¥{{reward_price}}
27
{{like_count}}
{{collect_count}}
添加回复 ({{post_count}})

相关推荐

快速安全登录

使用微信扫码登录
{{item.label}} 加精
{{item.label}} {{item.label}} 板块推荐 常见问题 产品动态 精选推荐 首页头条 首页动态 首页推荐
取 消 确 定
回复
回复
问题:
问题自动获取的帖子内容,不准确时需要手动修改. [获取答案]
答案:
提交
bug 需求 取 消 确 定
打赏金额
当前余额:¥{{rewardUserInfo.reward_price}}
{{item.price}}元
请输入 0.1-{{reward_max_price}} 范围内的数值
打赏成功
¥{{price}}
完成 确认打赏

微信登录/注册

切换手机号登录

{{ bind_phone ? '绑定手机' : '手机登录'}}

{{codeText}}
切换微信登录/注册
暂不绑定
CRMEB客服

CRMEB咨询热线 咨询热线

400-8888-794

微信扫码咨询

CRMEB开源商城下载 源码下载 CRMEB帮助文档 帮助文档
返回顶部 返回顶部
CRMEB客服