一、接口体系概览
京东开放平台为开发者提供了丰富的API矩阵,主要涵盖以下核心能力:
| 接口类型 | 方法名 | 适用场景 | 权限要求 |
|---|---|---|---|
| 商品详情 | jd.union.open.goods.query / jd.union.open.goods.bigfield.query | 获取SKU基础信息、大字段详情 | 京东联盟账号+应用授权 |
| 关键词搜索 | jd.union.open.goods.search | 按关键词检索商品列表 | 基础权限即可 |
| 评论数据 | jd.union.open.goods.search (含评论字段) | 获取好评率、评论数 | 进阶权限 |
| 券后价/佣金 | jd.union.open.goods.query | 获取优惠券、佣金、到手价 | 联盟高级权限+推广位绑定 接口统一地址:https://api.jd.com/routerjson |
二、接入准备
2.1 账号注册与权限申请
- 注册开发者账号:访问京东开放平台,完成实名认证(企业用户需提交营业执照+近3个月经营流水)
- 创建应用:选择「自研应用」或「联盟应用」类型,提交审核
- 获取密钥:审核通过后获取 App Key 和 App Secret
- 申请接口权限:在「服务管理」中申请对应接口权限
2026年权限分级新规:
| 权限等级 | 适用人群 | 可获取数据 | QPS限制 | 申请要求 |
|---|---|---|---|---|
| 基础权限 | 个人开发者 | 商品名称、价格、主图、基础销量 | 5 | 实名认证 |
| 进阶权限 | 企业用户 | +促销详情、评价摘要、店铺评分、优惠券 | 20 | 企业营业执照 |
| 高级权限 | 联盟合作伙伴 | +实时销量、商品成长指数、点击转化率 | 60 | 数据用途承诺书 |
三、核心接口详解
3.1 商品详情接口
接口方法:jd.union.open.goods.query(基础详情)/ jd.union.open.goods.bigfield.query(大字段详情)
功能说明:
- 通过SKU ID获取商品完整信息
- 包含价格、库存、品牌、类目、店铺信息
- 大字段接口额外返回图文详情、规格参数等
- 请求参数:
{
"method": "jd.union.open.goods.query",
"app_key": "your_app_key",
"access_token": "your_access_token",
"timestamp": "2026-04-30 15:44:00",
"format": "json",
"v": "1.0",
"sign_method": "md5",
"360buy_param_json": {
"skuIds": "10335871600", // 商品SKU ID,支持批量
"fields": "skuId,title,price,lowestPrice,commissionRate,commission,couponInfo,goodComments,totalComments,score,shopName,isSelf,volume,imgUrl"
}
}
返回字段说明
| 字段 | 类型 | 说明 |
|---|---|---|
skuId | Long | 商品SKU ID |
title / productName | String | 商品标题 |
price | Double | 当前售价 |
lowestPrice | Double | 历史最低价 |
commissionRate | Double | 佣金比例(%) |
commission | Double | 佣金金额(元) |
couponInfo | Object | 优惠券信息(含面额、使用门槛) |
purchasePrice | Double | 到手价(已计算优惠券抵扣) |
goodComments | Int | 好评数 |
totalComments | Int | 总评论数 |
score | Double | 商品评分 |
volume | Int | 30天销量 |
isSelf | Int | 是否自营(1是/0否) |
3.2 关键词搜索接口
接口方法:jd.union.open.goods.search
核心能力:
- 支持关键词模糊匹配与多词组合(空格分隔)
- 支持价格区间、类目、优惠券、自营等维度筛选
- 支持按价格、销量、佣金、评分、成长指数排序
- 请求参数:
{
"360buy_param_json": {
"keyword": "无线蓝牙耳机 主动降噪", // 搜索关键词
"pageIndex": 1, // 页码(1-50)
"pageSize": 20, // 每页数量(1-50)
"priceFrom": 100.00, // 价格区间起
"priceTo": 500.00, // 价格区间止
"sortName": "sales", // 排序字段
"sort": "desc", // 排序方式
"hasCoupon": 1, // 是否有券(1有/0不限)
"isSelf": 1, // 是否自营(1是/0否)
"goodRate": 92, // 最低好评率(80-100)
"cid3": 12052, // 三级类目ID
"fields": "skuId,productName,price,commission,couponInfo,goodComments,score,volume"
}
}
2026年新增参数:
表格
| 参数 | 类型 | 说明 |
|---|---|---|
growthScore | Int | 商品成长指数(≥80为潜力爆款) |
shortVideoHot | Boolean | 短视频高热度筛选 |
clickRate | Double | 实时点击转化率 |
3.3 评论数据接口
京东评论数据主要通过搜索接口的字段返回,无独立评论详情接口(需申请特殊权限):
可获取的评论维度:
- goodComments:好评数量
- totalComments:总评论数
- score:综合评分(1-5分)
- goodRate:好评率百分比
- 注意:评价原文涉及用户隐私,需单独申请「评价内容权限」,并严格遵守数据保护法规。
3.4 券后价与佣金计算
券后价(到手价)计算逻辑:
到手价 = 促销价 - 优惠券面额
券后佣金 = 到手价 × 佣金比例
优惠券数据结构:
{
"couponInfo": {
"couponList": [
{
"bindType": 1, // 券类型
"discount": 20.00, // 优惠面额
"quota": 99.00, // 使用门槛(满99减20)
"platformType": 0, // 平台券/店铺券
"getStartTime": 1714464000000, // 领取开始时间
"getEndTime": 1717056000000, // 领取结束时间
"useStartTime": 1714464000000, // 使用开始时间
"useEndTime": 1717056000000 // 使用结束时间
}
]
},
"purchasePriceInfo": {
"purchasePrice": 79.00 // 最终到手价
}
}
四、签名认证机制
京东API采用MD5签名或HMAC-SHA256进行请求认证。
4.1 MD5签名算法(标准版)
签名步骤:
- 参数排序:将所有业务参数按参数名ASCII升序排序
- 拼接字符串:appSecret + key1 + value1 + key2 + value2 + ... + appSecret
- MD5加密:对拼接字符串进行MD5哈希,结果转大写
Python实现:
import hashlib
import urllib.parse
import json
import time
class JDAPIClient:
def __init__(self, app_key, app_secret, access_token):
self.app_key = app_key
self.app_secret = app_secret
self.access_token = access_token
self.api_url = "https://api.jd.com/routerjson"
def generate_sign(self, params: dict) -> str:
"""生成MD5签名"""
# 1. 过滤空值并排序
sorted_params = sorted(
[(k, v) for k, v in params.items() if v is not None],
key=lambda x: x[0]
)
# 2. 拼接字符串
sign_str = self.app_secret
for key, value in sorted_params:
# URL编码value
encoded_value = urllib.parse.quote(str(value), safe='')
sign_str += f"{key}{encoded_value}"
sign_str += self.app_secret
# 3. MD5加密并转大写
return hashlib.md5(sign_str.encode('utf-8')).hexdigest().upper()
def build_request(self, method, business_params):
"""构建完整请求"""
timestamp = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
params = {
"method": method,
"app_key": self.app_key,
"access_token": self.access_token,
"timestamp": timestamp,
"format": "json",
"v": "1.0",
"sign_method": "md5",
"360buy_param_json": json.dumps(business_params, ensure_ascii=False)
}
# 生成签名
params["sign"] = self.generate_sign(params)
return params
4.2 HMAC-SHA256签名(高级版)
部分新版接口要求使用HMAC-SHA256:
import hmac
import hashlib
def generate_hmac_sign(params, app_secret):
sorted_params = sorted(params.items(), key=lambda x: x[0])
sign_str = "&".join(f"{k}={urllib.parse.quote_plus(str(v))}" for k, v in sorted_params)
signature = hmac.new(
app_secret.encode('utf-8'),
sign_str.encode('utf-8'),
hashlib.sha256
).hexdigest().upper()
return signature
五、完整实战代码
5.1 商品详情查询
import requests
from typing import Dict, Optional
class JDGoodsAPI:
def __init__(self, app_key: str, app_secret: str, access_token: str):
self.client = JDAPIClient(app_key, app_secret, access_token)
def get_goods_detail(self, sku_id: str, fields: Optional[str] = None) -> Dict:
"""
获取商品详情
"""
if not fields:
fields = ("skuId,title,price,lowestPrice,commissionRate,commission,"
"couponInfo,purchasePriceInfo,goodComments,totalComments,"
"score,shopName,isSelf,volume,imgUrl,materialUrl")
business_params = {
"skuIds": sku_id,
"fields": fields
}
params = self.client.build_request(
"jd.union.open.goods.query",
business_params
)
try:
response = requests.get(self.client.api_url, params=params, timeout=30)
result = response.json()
if "error_response" in result:
error = result["error_response"]
return {"success": False, "error": error.get("msg")}
data = result.get("jd_union_open_goods_query_response", {})
goods_list = data.get("result", [])
if not goods_list:
return {"success": False, "error": "商品不存在"}
return {"success": True, "data": self._format_goods(goods_list[0])}
except Exception as e:
return {"success": False, "error": str(e)}
def _format_goods(self, item: dict) -> dict:
"""格式化商品数据"""
coupon_info = item.get("couponInfo", {})
coupons = coupon_info.get("couponList", []) if isinstance(coupon_info, dict) else []
# 计算券后价
price = float(item.get("price", 0))
best_coupon = max(coupons, key=lambda x: x.get("discount", 0)) if coupons else None
coupon_amount = best_coupon.get("discount", 0) if best_coupon else 0
final_price = round(price - coupon_amount, 2)
return {
"sku_id": item.get("skuId"),
"title": item.get("title") or item.get("productName"),
"price": price,
"lowest_price": float(item.get("lowestPrice", 0)),
"coupon_amount": coupon_amount,
"final_price": final_price,
"commission_rate": f"{item.get('commissionRate', 0)}%",
"commission": item.get("commission"),
"has_coupon": bool(coupons),
"coupon_detail": best_coupon,
"shop_name": item.get("shopName"),
"is_self": item.get("isSelf") == 1,
"sales_volume": item.get("volume"),
"good_comments": item.get("goodComments"),
"total_comments": item.get("totalComments"),
"good_rate": item.get("score"),
"image": item.get("imgUrl"),
"product_url": f"https://item.jd.com/{item.get('skuId')}.html"
}
# 使用示例
if __name__ == "__main__":
api = JDGoodsAPI(
app_key="your_app_key",
app_secret="your_app_secret",
access_token="your_access_token"
)
result = api.get_goods_detail("10335871600")
if result["success"]:
goods = result["data"]
print(f"商品:{goods['title']}")
print(f"原价:¥{goods['price']}")
print(f"券后价:¥{goods['final_price']} (省¥{goods['coupon_amount']})")
print(f"佣金比例:{goods['commission_rate']}")
print(f"销量:{goods['sales_volume']}")
else:
print(f"查询失败:{result['error']}")
5.2 关键词搜索(含券后价筛选)
class JDSearchAPI(JDGoodsAPI):
def search_goods(
self,
keyword: str,
page: int = 1,
page_size: int = 20,
price_range: tuple = None,
has_coupon: bool = False,
min_good_rate: int = None,
sort: str = "sales_desc"
) -> Dict:
"""
关键词搜索商品
"""
sort_mapping = {
"price_asc": ("price", "asc"),
"price_desc": ("price", "desc"),
"sales_desc": ("volume", "desc"),
"commission_desc": ("commissionRate", "desc"),
"rating_desc": ("score", "desc"),
"growth_desc": ("growthScore", "desc") # 2026新增
}
business_params = {
"keyword": keyword,
"pageIndex": page,
"pageSize": min(max(page_size, 1), 50),
"fields": ("skuId,productName,price,lowestPrice,commissionRate,commission,"
"couponInfo,purchasePriceInfo,goodComments,totalComments,score,"
"shopName,isSelf,volume,imgUrl,growthScore")
}
# 价格区间
if price_range and len(price_range) == 2:
business_params["priceFrom"] = price_range[0]
business_params["priceTo"] = price_range[1]
# 排序
if sort in sort_mapping:
business_params["sortName"], business_params["sort"] = sort_mapping[sort]
# 优惠券筛选
if has_coupon:
business_params["hasCoupon"] = 1
# 好评率筛选
if min_good_rate and 80 <= min_good_rate <= 100:
business_params["goodRate"] = min_good_rate
params = self.client.build_request(
"jd.union.open.goods.search",
business_params
)
try:
response = requests.get(self.client.api_url, params=params, timeout=30)
result = response.json()
if "error_response" in result:
return {"success": False, "error": result["error_response"].get("msg")}
data = result.get("jd_union_open_goods_search_response", {})
search_result = data.get("result", {})
goods_list = search_result.get("data", [])
total = search_result.get("totalCount", 0)
# 数据清洗
items = [self._format_goods(item) for item in goods_list]
# 券后价二次筛选(如果API返回的purchasePrice不准确)
if has_coupon:
items = [item for item in items if item["has_coupon"]]
return {
"success": True,
"total": total,
"page": page,
"items": items
}
except Exception as e:
return {"success": False, "error": str(e)}
# 搜索示例
if __name__ == "__main__":
search_api = JDSearchAPI(
app_key="your_app_key",
app_secret="your_app_secret",
access_token="your_access_token"
)
# 搜索"保温杯",10-50元,有优惠券,按销量排序
result = search_api.search_goods(
keyword="保温杯",
price_range=(10, 50),
has_coupon=True,
sort="sales_desc",
min_good_rate=95
)
if result["success"]:
print(f"找到 {result['total']} 件商品,当前第{result['page']}页")
for item in result["items"][:5]:
print(f"\n【{item['title'][:30]}...】")
print(f" 券后价:¥{item['final_price']} | 佣金:{item['commission_rate']}")
print(f" 销量:{item['sales_volume']} | 好评率:{item['good_rate']}")
六、错误处理与限流策略
6.1 常见错误码
| 错误码 | 含义 | 解决方案 |
|---|---|---|
| 1001 | 签名错误 | 检查参数排序、编码、密钥是否正确 |
| 2001 | 商品ID无效 | 确认SKU ID存在且已上架 |
| 429 | 请求频率超限 | 降低QPS,增加请求间隔 |
| 500/502/503 | 服务端错误 | 启用指数退避重试 |
6.2 限流与重试机制
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry
import time
class JDAPIClient:
def __init__(self, app_key, app_secret, access_token):
# ... 原有初始化 ...
# 配置重试机制
self.session = requests.Session()
retry = Retry(
total=3,
backoff_factor=0.5, # 间隔 0.5, 1, 2 秒
status_forcelist=[429, 500, 502, 503]
)
self.session.mount('https://', HTTPAdapter(max_retries=retry))
def request_with_rate_limit(self, params):
"""带频率控制的请求"""
time.sleep(1.5) # 基础QPS限制:每秒不超过1次(基础权限)
return self.session.get(self.api_url, params=params, timeout=30)
七、合规与注意事项
- 数据使用合规:不得将数据用于非法用途,严格遵守《京东开放平台开发者协议》
- 密钥安全:App Secret 禁止硬编码,建议使用环境变量或密钥管理服务
- 频率控制:基础权限QPS为5,超限可能导致IP被封禁
- 数据延迟:库存、价格数据可能存在5-10分钟延迟,重要场景建议搭配官方数据推送服务
- 评论隐私:评价原文需单独申请权限,禁止泄露用户个人信息
八、相关接口速查
| 功能 | 接口方法 | 文档 |
|---|---|---|
| 商品转链 | jd.union.open.promotion.common.get | 生成推广链接 |
| 订单查询 | jd.union.open.order.query | 查询推广订单及佣金 |
| 类目查询 | jd.union.open.category.goods.get | 获取商品分类树 |
| 优惠券查询 | jd.union.open.coupon.query | 查询优惠券详情 |
| 京粉精选 | jd.union.open.goods.jingfen.query | 获取推荐商品库 |
如遇任何疑问或有进一步的需求,请随时与我私信或者评论联系。

