在电商数据工具开发中,京东商品信息的获取通常依赖官方开放平台接口。jd.item_get 是京东提供的商品详情查询接口,能够返回商品标题、价格、库存、店铺信息等结构化数据,适用于ERP同步、竞品监控、选品分析等场景。本文将围绕该接口的接入流程、签名算法、请求实现、缓存优化和批量采集策略,提供一套可直接落地的开发方案。
调用代码节选:
# 系统演示、API测试控制台:http://console.open.onebound.cn/console/?i=NewRookie
{
"item": {
"num_iid": "10335871600",
"title": "xxxxxxxxxxxxxxxxx 42",
"desc_short": "xxxxxx",
"price": "189",
"promotion_price": "189",
"total_price": "",
"suggestive_price": "",
"orginal_price": "189",
"nick": "安xxxxxx",
"num": 33,
"min_num": 0,
"detail_url": "https://item.jd.com/10335871600.html#crumb-wrap",
"pic_url": "//img13.360buyimg.com/n1/jfs/t1/229337/37/10684/149167/65b9de38F890290bc/0e3cac8acb2252f7.jpg",
"brand": "xx(ANxxx)",
"brandId": "3552",
"rootCatId": "1318",
"cid": "9756",
一、前置准备:获取接口调用凭证
-
注册开发者账号
访问开放平台,完成企业或个人实名认证。个人开发者可申请部分接口,但商品详情接口通常要求企业资质。
-
创建应用并申请权限
在控制台创建应用,填写应用名称、类型和用途说明,提交商品详情相关接口(
jd.item.get)的权限申请。审核周期一般为1-3个工作日。 -
获取凭证
审核通过后,获得 App Key 和 App Secret 。这两个参数用于接口调用的身份验证和签名生成。如果涉及店铺数据托管(如获取店铺私有商品信息),还需要通过OAuth2.0流程获取 access_token,并在请求中携带。
二、核心请求参数说明
jd.item.get 接口的请求参数分为公共参数和业务参数。公共参数在每次调用中都必须携带,业务参数根据接口要求填写。
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| app_key | String | 是 | 应用标识,开放平台分配 |
| method | String | 是 | 固定值 jd.item.get |
| timestamp | String | 是 | 北京时间,格式 yyyy-MM-dd HH:mm:ss,用于防重放攻击 |
| v | String | 是 | 接口版本,固定为 2.0 |
| skuId / itemId | Long | 二选一 | skuId 为单品SKU编号,itemId 为多规格商品主ID。优先使用 skuId 查询更精准 |
| sign | String | 是 | MD5大写签名,生成规则见下文 |
| fields | String | 否 | 指定返回字段,逗号分隔,可减少响应体积 |
| area | String | 否 | 地区编码,不传默认返回北京地区的价格和库存 |
timestamp 需使用北京时间,且与京东服务器时间偏差不能超过5分钟,否则会返回时间错误。建议在服务器上配置NTP同步时间。
三、签名算法实现
API签名采用MD5算法,具体规则如下:
-
将所有请求参数(包括公共参数和业务参数)按参数名的ASCII码升序排列。
-
将排序后的参数拼接为
key1value1key2value2...的格式。 -
在拼接串前后各加上 App Secret。
-
对整体字符串进行MD5加密,结果转换为大写。
Python实现:
python
import hashlib
import time
import requests
def generate_sign(params: dict, app_secret: str) -> str:
"""
生成API MD5签名
:param params: 所有请求参数(不包含sign)
:param app_secret: 应用密钥
:return: 大写MD5签名
"""
sorted_items = sorted(params.items(), key=lambda x: x[0])
raw = app_secret + ''.join(f"{k}{v}" for k, v in sorted_items) + app_secret
return hashlib.md5(raw.encode('utf-8')).hexdigest().upper()
四、完整请求示例(含错误处理与重试)
以下是一个生产可用的京东商品详情查询封装,包含签名、请求、超时重试和错误处理。
python
import hashlib
import time
import requests
from typing import Optional, Dict, Any
class JdItemClient:
def __init__(self, app_key: str, app_secret: str):
self.app_key = app_key
self.app_secret = app_secret
self.gateway = "https://api.jd.com/routerjson"
def _sign(self, params: Dict[str, Any]) -> str:
sorted_items = sorted(params.items(), key=lambda x: x[0])
raw = self.app_secret + ''.join(f"{k}{v}" for k, v in sorted_items) + self.app_secret
return hashlib.md5(raw.encode('utf-8')).hexdigest().upper()
def get_item(self, sku_id: Optional[int] = None, item_id: Optional[int] = None,
fields: str = "skuId,title,price,stock,shopInfo,images",
retries: int = 3) -> Optional[Dict[str, Any]]:
"""
获取商品详情,带重试机制
"""
if not sku_id and not item_id:
raise ValueError("skuId 和 itemId 至少提供一个")
params = {
"app_key": self.app_key,
"method": "jd.item.get",
"timestamp": time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()),
"v": "2.0",
"fields": fields
}
if sku_id:
params["skuId"] = sku_id
else:
params["itemId"] = item_id
params["sign"] = self._sign(params)
for attempt in range(retries):
try:
resp = requests.post(self.gateway, data=params, timeout=10)
resp.raise_for_status()
result = resp.json()
if result.get("code") == "0":
return result.get("data", {})
else:
print(f"接口返回错误: code={result.get('code')}, msg={result.get('msg')}")
if result.get("code") in ["501", "502", "503"]: # 系统级错误可重试
time.sleep(2 ** attempt)
continue
return None
except requests.RequestException as e:
print(f"请求异常: {e}")
if attempt < retries - 1:
time.sleep(2 ** attempt)
else:
return None
return None
五、返回数据字段解析
接口返回的 data 对象包含商品核心字段,常见结构如下:
-
基础信息 :
title(标题)、price(当前售价)、originalPrice(划线价)、sales(近30天销量)、commentCount(评价数)、goodRate(好评率) -
多媒体 :
images(轮播图列表)、mainImage(主图)、detailHtml(商品详情HTML) -
规格库存 :
skus(全量SKU列表,包含每个SKU的skuId、price、stock) -
店铺信息 :
shopId、shopName、isSelfOperated(是否自营) -
营销信息 :
promotionInfo(满减规则)、couponInfo(优惠券)、finalPrice(券后价)
不同商品类型返回字段可能略有差异,建议根据 fields 参数按需获取,并对缺失字段做空值处理。
六、实战优化:缓存、批量采集与异常处理
1. Redis缓存降低调用量
京东接口有单秒频次和每日配额限制,对于高频查询的热门商品,建议使用Redis缓存。以下是一个简单的缓存包装:
python
import redis
import json
r = redis.Redis(host='localhost', port=6379, db=0, decode_responses=True)
def get_item_with_cache(client: JdItemClient, sku_id: int, ttl: int = 86400):
"""
带缓存的商品详情获取,默认缓存24小时
"""
cache_key = f"jd:item:{sku_id}"
cached = r.get(cache_key)
if cached:
return json.loads(cached)
item = client.get_item(sku_id=sku_id)
if item:
r.setex(cache_key, ttl, json.dumps(item, ensure_ascii=False))
return item
对于价格、库存等实时性要求高的字段,可以设置较短的TTL(如10分钟)或单独缓存。
2. 批量采集商品数据
如果需要获取大量商品详情,建议先通过搜索接口(如jd.item.search)批量获取商品ID,再逐个调用详情接口。为了避免触发限流,每两次请求之间应添加适当延时:
python
import time
def batch_fetch_items(client: JdItemClient, sku_ids: list, delay: float = 0.5):
results = []
for sku_id in sku_ids:
item = client.get_item(sku_id=sku_id)
if item:
results.append(item)
time.sleep(delay) # 控制频率,视QPS配额调整
return results
3. 图片资源处理
接口返回的图片是京东CDN地址,长期使用建议下载到自有服务器或对象存储,避免京东调整域名导致图片失效。可使用异步任务批量下载:
python
def download_image(url: str, save_path: str):
resp = requests.get(url, stream=True, timeout=10)
if resp.status_code == 200:
with open(save_path, 'wb') as f:
for chunk in resp.iter_content(1024):
f.write(chunk)
4. 异常处理与日志
完整记录每次请求的参数和响应,便于排查问题。可以使用Python的logging模块:
python
import logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
logging.info(f"请求参数: {params}, 响应: {resp.text}")
对于错误码,可建立映射表,快速定位问题。常见错误码如:
-
10001:app_key无效 -
10002:签名错误 -
10003:接口权限不足 -
10004:频率超限
七、典型应用场景
-
跨平台ERP同步:通过定时任务拉取店铺商品,同步到自有ERP系统,实现库存和价格的双向更新。
-
竞品监控:定期抓取竞品价格、销量、促销信息,触发价格异动预警。
-
选品分析:整合品类全量商品数据,按销量、价格、评价等维度分析,辅助选品决策。
八、总结
京东开放平台的 jd.item_get 接口是获取商品详情的稳定通道。开发时重点做好三件事:
-
签名算法准确:参数排序、拼接、MD5大写缺一不可。
-
缓存与限流:通过Redis缓存降低调用频率,避免触发平台风控。
-
健壮的错误处理:网络超时重试、错误码分支处理、日志留痕。
接口本身并不复杂,但生产环境中细节决定成败。合理利用缓存和批量策略,可以在保障数据时效性的同时,最大化接口配额的使用效率。