在工業(yè)供應(yīng)鏈數(shù)字化轉(zhuǎn)型過程中,京東工業(yè)平臺(tái)作為專注于工業(yè)用品采購(gòu)的 B2B 電商平臺(tái),其商品詳情數(shù)據(jù)包含豐富的技術(shù)參數(shù)、合規(guī)認(rèn)證和供應(yīng)鏈信息,對(duì)企業(yè)采購(gòu)系統(tǒng)、供應(yīng)鏈管理工具的開發(fā)具有重要價(jià)值。本文將詳細(xì)介紹京東工業(yè)平臺(tái)商品詳情接口的調(diào)用流程,包括 OAuth2.0 認(rèn)證機(jī)制、簽名生成、工業(yè)特性數(shù)據(jù)解析及完整代碼實(shí)現(xiàn),幫助開發(fā)者快速構(gòu)建穩(wěn)定高效的工業(yè)商品數(shù)據(jù)對(duì)接功能。
一、京東工業(yè)商品詳情接口基礎(chǔ)信息
京東工業(yè)開放平臺(tái)提供的jd.industry.product.detail.get接口是獲取商品完整信息的核心接口,專為工業(yè)場(chǎng)景設(shè)計(jì),相比消費(fèi)類商品接口增加了大量專業(yè)維度的數(shù)據(jù)。
接口特點(diǎn):
采用 OAuth2.0 + 簽名雙重認(rèn)證機(jī)制,安全性更高
支持獲取工業(yè)商品特有的技術(shù)參數(shù)、規(guī)格型號(hào)、認(rèn)證資質(zhì)等信息
包含詳細(xì)的包裝、物流、售后服務(wù)等供應(yīng)鏈關(guān)鍵數(shù)據(jù)
提供多維度價(jià)格體系(零售、批發(fā)、企業(yè)集采等)
接口端點(diǎn):https://api.jd.com/routerjson
二、認(rèn)證機(jī)制與核心參數(shù)解析
1. 完整認(rèn)證流程
京東工業(yè) API 采用業(yè)界標(biāo)準(zhǔn)的 OAuth2.0 認(rèn)證框架,結(jié)合簽名機(jī)制確保接口安全:
獲取 Access Token:通過 client_id 和 client_secret 獲取訪問令牌(有效期 24 小時(shí))
生成簽名:對(duì)請(qǐng)求參數(shù)按規(guī)則進(jìn)行簽名計(jì)算
接口調(diào)用:在請(qǐng)求中攜帶 Access Token 和簽名信息
2. 簽名生成規(guī)則
收集所有請(qǐng)求參數(shù)(包括公共參數(shù)和業(yè)務(wù)參數(shù))
按參數(shù)名 ASCII 碼升序排序
拼接為 "key=value" 形式的字符串,用 & 連接
拼接上 Access Token 和 app_secret,形成待簽名字符串
使用 MD5 算法對(duì)字符串進(jìn)行加密,得到 32 位大寫簽名
3. 核心參數(shù)說明
公共參數(shù):
method:接口名稱,固定為jd.industry.product.detail.get
app_key:應(yīng)用唯一標(biāo)識(shí)
access_token:訪問令牌
timestamp:時(shí)間戳(毫秒級(jí))
format:響應(yīng)格式,固定為 json
v:API 版本,固定為 1.0
sign:簽名值
業(yè)務(wù)參數(shù):
productId:商品 ID(必填,可從搜索接口獲取)
needTechParam:是否需要技術(shù)參數(shù)(true/false,默認(rèn) false)
needCert:是否需要認(rèn)證信息(true/false,默認(rèn) false)
needInventory:是否需要庫(kù)存信息(true/false,默認(rèn) false)

三、完整代碼實(shí)現(xiàn)
以下是 Python 實(shí)現(xiàn)的京東工業(yè)商品詳情接口調(diào)用功能,包含完整的認(rèn)證流程、簽名生成和工業(yè)數(shù)據(jù)解析:
import requests
import time
import hashlib
import json
from typing import Dict, List, Optional, Any
class JDIndustryProductAPI:
def __init__(self, app_key: str, app_secret: str, redirect_uri: str):
"""
初始化京東工業(yè)商品API客戶端
:param app_key: 應(yīng)用的App Key
:param app_secret: 應(yīng)用的App Secret
:param redirect_uri: 授權(quán)回調(diào)地址
"""
self.app_key = app_key
self.app_secret = app_secret
self.redirect_uri = redirect_uri
self.base_url = "https://api.jd.com/routerjson"
self.token_url = "https://oauth.jd.com/token"
self.access_token = None
self.token_expiry = 0 # 令牌過期時(shí)間戳(秒)
def get_auth_url(self) -> str:
"""生成授權(quán)URL,用于獲取code(首次授權(quán)時(shí)使用)"""
params = {
"response_type": "code",
"client_id": self.app_key,
"redirect_uri": self.redirect_uri,
"state": "JD_INDUSTRY_STATE"
}
return f"https://oauth.jd.com/authorize?{requests.compat.urlencode(params)}"
def get_access_token(self, code: Optional[str] = None, refresh_token: Optional[str] = None) -> bool:
"""
獲取或刷新訪問令牌
:param code: 授權(quán)碼(首次獲取時(shí)需要)
:param refresh_token: 刷新令牌(令牌過期時(shí)使用)
:return: 是否成功
"""
params = {
"client_id": self.app_key,
"client_secret": self.app_secret,
"grant_type": "authorization_code" if code else "refresh_token"
}
if code:
params["code"] = code
params["redirect_uri"] = self.redirect_uri
elif refresh_token:
params["refresh_token"] = refresh_token
else:
return False
try:
response = requests.post(self.token_url, data=params, timeout=10)
result = response.json()
if "access_token" in result:
self.access_token = result["access_token"]
expires_in = result.get("expires_in", 86400)
self.token_expiry = time.time() + expires_in
self.refresh_token = result.get("refresh_token")
return True
else:
print(f"獲取令牌失敗: {result.get('error_description')}")
return False
except Exception as e:
print(f"令牌請(qǐng)求異常: {str(e)}")
return False
def _generate_sign(self, params: Dict[str, str]) -> str:
"""生成API請(qǐng)求簽名"""
# 按參數(shù)名ASCII升序排序
sorted_params = sorted(params.items(), key=lambda x: x[0])
# 拼接參數(shù)
query_string = "&".join([f"{k}={v}" for k, v in sorted_params])
# 拼接access_token和app_secret
sign_str = f"{query_string}&access_token={self.access_token}{self.app_secret}"
# 計(jì)算MD5簽名并轉(zhuǎn)為大寫
return hashlib.md5(sign_str.encode('utf-8')).hexdigest().upper()
def get_product_detail(self,
product_id: str,
need_tech_param: bool = True,
need_cert: bool = True,
need_inventory: bool = True) -> Dict[str, Any]:
"""
獲取京東工業(yè)商品詳情
:param product_id: 商品ID
:param need_tech_param: 是否需要技術(shù)參數(shù)
:param need_cert: 是否需要認(rèn)證信息
:param need_inventory: 是否需要庫(kù)存信息
:return: 商品詳情數(shù)據(jù)
"""
# 檢查令牌有效性
if not self.access_token or time.time() >= self.token_expiry:
if not self.refresh_token or not self.get_access_token(refresh_token=self.refresh_token):
return {"success": False, "error_msg": "訪問令牌無效或已過期"}
# 業(yè)務(wù)參數(shù)
biz_params = {
"productId": product_id,
"needTechParam": str(need_tech_param).lower(),
"needCert": str(need_cert).lower(),
"needInventory": str(need_inventory).lower()
}
# 公共參數(shù)
params = {
"method": "jd.industry.product.detail.get",
"app_key": self.app_key,
"timestamp": str(int(time.time() * 1000)), # 毫秒級(jí)時(shí)間戳
"format": "json",
"v": "1.0",
"param_json": json.dumps(biz_params, ensure_ascii=False)
}
# 生成簽名
params["sign"] = self._generate_sign(params)
try:
# 發(fā)送請(qǐng)求
response = requests.post(
self.base_url,
data=params,
timeout=15
)
response.raise_for_status()
# 解析響應(yīng)
result = response.json()
# 處理API錯(cuò)誤
if "error_response" in result:
error = result["error_response"]
return {
"success": False,
"error_code": error.get("code"),
"error_msg": error.get("msg")
}
# 處理正常響應(yīng)
detail_data = result.get("jd_industry_product_detail_get_response", {}).get("result", {})
return self._parse_product_detail(detail_data)
except requests.exceptions.RequestException as e:
return {
"success": False,
"error_msg": f"請(qǐng)求異常: {str(e)}"
}
except Exception as e:
return {
"success": False,
"error_msg": f"處理響應(yīng)失敗: {str(e)}"
}
def _parse_product_detail(self, raw_data: Dict[str, Any]) -> Dict[str, Any]:
"""解析原始商品詳情數(shù)據(jù)為結(jié)構(gòu)化格式"""
if not raw_data:
return {"success": False, "error_msg": "無商品詳情數(shù)據(jù)"}
# 基礎(chǔ)信息解析
base_info = {
"product_id": raw_data.get("productId"),
"sku_id": raw_data.get("skuId"),
"name": raw_data.get("name"),
"brand": {
"id": raw_data.get("brandId"),
"name": raw_data.get("brandName")
},
"category": {
"id": raw_data.get("categoryId"),
"name": raw_data.get("categoryName"),
"parent_id": raw_data.get("parentCategoryId"),
"parent_name": raw_data.get("parentCategoryName")
},
"model": raw_data.get("model"), # 型號(hào)
"spec": raw_data.get("spec"), # 規(guī)格
"production_date": raw_data.get("productionDate"), # 生產(chǎn)日期
"warranty_period": raw_data.get("warrantyPeriod"), # 保修期
"url": raw_data.get("productUrl")
}
# 價(jià)格信息解析
price_info = {
"retail_price": raw_data.get("retailPrice"), # 零售價(jià)
"wholesale_price": self._parse_wholesale_price(raw_data.get("wholesalePriceList", [])), # 批發(fā)價(jià)
"enterprise_price": raw_data.get("enterprisePrice"), # 企業(yè)集采價(jià)
"currency": raw_data.get("currency", "CNY"),
"tax_included": raw_data.get("taxIncluded", True) # 是否含稅
}
# 技術(shù)參數(shù)解析
tech_params = []
for group in raw_data.get("techParamGroups", []):
group_params = []
for param in group.get("params", []):
group_params.append({
"name": param.get("name"),
"value": param.get("value"),
"unit": param.get("unit"),
"standard": param.get("standard") # 執(zhí)行標(biāo)準(zhǔn)
})
tech_params.append({
"group_name": group.get("groupName"),
"params": group_params
})
# 認(rèn)證信息解析
certifications = []
for cert in raw_data.get("certifications", []):
certifications.append({
"type": cert.get("type"), # 認(rèn)證類型
"number": cert.get("number"), # 認(rèn)證編號(hào)
"issuer": cert.get("issuer"), # 發(fā)證機(jī)構(gòu)
"issue_date": cert.get("issueDate"), # 發(fā)證日期
"expiry_date": cert.get("expiryDate"), # 有效期至
"image_url": cert.get("imageUrl") # 認(rèn)證證書圖片
})
# 庫(kù)存信息解析
inventory = {
"total_stock": raw_data.get("totalStock"),
"warehouses": []
}
for wh in raw_data.get("warehouseInventories", []):
inventory["warehouses"].append({
"id": wh.get("warehouseId"),
"name": wh.get("warehouseName"),
"location": wh.get("location"), # 倉(cāng)庫(kù)位置
"stock": wh.get("stock"),
"lock_stock": wh.get("lockStock") # 鎖定庫(kù)存
})
# 包裝與物流信息
logistics = {
"packaging": {
"length": raw_data.get("packageLength"),
"width": raw_data.get("packageWidth"),
"height": raw_data.get("packageHeight"),
"weight": raw_data.get("packageWeight"),
"unit": raw_data.get("packageUnit")
},
"delivery": {
"min_delivery_days": raw_data.get("minDeliveryDays"),
"max_delivery_days": raw_data.get("maxDeliveryDays"),
"support_batch": raw_data.get("supportBatch", False), # 是否支持批量發(fā)貨
"special_logistics": raw_data.get("specialLogistics", False) # 是否需要特殊物流
}
}
# 售后服務(wù)信息
after_sales = {
"support_return": raw_data.get("supportReturn", False),
"return_days": raw_data.get("returnDays"),
"maintenance_service": raw_data.get("maintenanceService", []), # 維修服務(wù)
"technical_support": raw_data.get("technicalSupport", False) # 是否提供技術(shù)支持
}
return {
"success": True,
"base_info": base_info,
"price_info": price_info,
"tech_params": tech_params,
"certifications": certifications,
"inventory": inventory,
"logistics": logistics,
"after_sales": after_sales,
"images": {
"main_images": raw_data.get("mainImages", []),
"detail_images": raw_data.get("detailImages", []),
"tech_images": raw_data.get("techImages", []), # 技術(shù)圖紙
"cert_images": raw_data.get("certImages", []) # 認(rèn)證證書圖片
}
}
def _parse_wholesale_price(self, wholesale_data: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
"""解析批發(fā)價(jià)格體系"""
wholesale_prices = []
for item in wholesale_data:
wholesale_prices.append({
"min_quantity": item.get("minQuantity"),
"max_quantity": item.get("maxQuantity"),
"price": item.get("price"),
"discount": item.get("discount") # 折扣比例
})
return wholesale_prices
# 使用示例
if __name__ == "__main__":
# 替換為你的應(yīng)用信息
APP_KEY = "your_app_key"
APP_SECRET = "your_app_secret"
REDIRECT_URI = "your_redirect_uri"
# 初始化API客戶端
jd_industry_api = JDIndustryProductAPI(APP_KEY, APP_SECRET, REDIRECT_URI)
# 首次使用需要獲取授權(quán)碼
# print("請(qǐng)?jiān)L問以下URL進(jìn)行授權(quán):")
# print(jd_industry_api.get_auth_url())
# code = input("請(qǐng)輸入授權(quán)后獲取的code: ")
# jd_industry_api.get_access_token(code=code)
# 已獲取過token的情況,可直接使用refresh_token刷新
# jd_industry_api.refresh_token = "your_refresh_token"
# jd_industry_api.get_access_token(refresh_token=jd_industry_api.refresh_token)
# 示例:獲取商品詳情(替換為實(shí)際商品ID)
if jd_industry_api.access_token:
product_detail = jd_industry_api.get_product_detail(
product_id="100012345678",
need_tech_param=True,
need_cert=True,
need_inventory=True
)
if product_detail["success"]:
print(f"商品名稱: {product_detail['base_info']['name']}")
print(f"型號(hào): {product_detail['base_info']['model']}")
print(f"零售價(jià): {product_detail['price_info']['retail_price']}{product_detail['price_info']['currency']}")
print(f"技術(shù)參數(shù)組數(shù): {len(product_detail['tech_params'])}")
print(f"認(rèn)證數(shù)量: {len(product_detail['certifications'])}")
print(f"總庫(kù)存: {product_detail['inventory']['total_stock']}")
else:
print(f"獲取失敗: {product_detail['error_msg']}(錯(cuò)誤碼: {product_detail.get('error_code')})")
else:
print("無法獲取有效的訪問令牌")
四、代碼核心功能解析
1. 認(rèn)證機(jī)制實(shí)現(xiàn)
完整實(shí)現(xiàn) OAuth2.0 認(rèn)證流程,支持首次授權(quán)和令牌刷新
自動(dòng)處理令牌過期問題,確保接口調(diào)用連續(xù)性
提供授權(quán) URL 生成方法,簡(jiǎn)化首次接入流程
2. 工業(yè)數(shù)據(jù)解析增強(qiáng)
針對(duì)工業(yè)商品特性設(shè)計(jì)數(shù)據(jù)結(jié)構(gòu),重點(diǎn)解析技術(shù)參數(shù)、認(rèn)證信息等專業(yè)字段
提取多維度價(jià)格體系(零售 / 批發(fā) / 企業(yè)集采),適配 B2B 采購(gòu)場(chǎng)景
解析庫(kù)存分布、物流信息和售后服務(wù),滿足供應(yīng)鏈管理需求
3. 簽名與安全優(yōu)化
嚴(yán)格按照京東工業(yè) API 規(guī)范實(shí)現(xiàn)簽名生成邏輯
采用毫秒級(jí)時(shí)間戳,避免時(shí)間同步問題導(dǎo)致的簽名失效
完整保留參數(shù)處理邏輯,確保簽名準(zhǔn)確性
4. 錯(cuò)誤處理機(jī)制
統(tǒng)一返回格式,包含成功標(biāo)識(shí)、業(yè)務(wù)數(shù)據(jù)及錯(cuò)誤信息
處理令牌無效、過期等常見認(rèn)證問題
捕獲 HTTP 請(qǐng)求異常,提供詳細(xì)的故障排查依據(jù)
五、實(shí)戰(zhàn)注意事項(xiàng)
1. 接口權(quán)限與申請(qǐng)
京東工業(yè) API 需企業(yè)資質(zhì)申請(qǐng),個(gè)人開發(fā)者無法接入
不同等級(jí)的企業(yè)賬號(hào)擁有不同的接口權(quán)限,高級(jí)權(quán)限需單獨(dú)申請(qǐng)
部分敏感數(shù)據(jù)(如詳細(xì)庫(kù)存分布)需要特殊權(quán)限審批
2. 調(diào)用策略優(yōu)化
技術(shù)參數(shù)和認(rèn)證信息等數(shù)據(jù)更新頻率低,建議本地緩存(6-24 小時(shí))
庫(kù)存數(shù)據(jù)實(shí)時(shí)性要求高,建議按需實(shí)時(shí)獲取
批量獲取商品詳情時(shí),需控制請(qǐng)求頻率(建議 QPS≤5)
3. 工業(yè)場(chǎng)景適配
型號(hào)和規(guī)格是工業(yè)商品的核心標(biāo)識(shí),需重點(diǎn)處理和存儲(chǔ)
認(rèn)證信息需驗(yàn)證有效期,對(duì)過期認(rèn)證商品進(jìn)行風(fēng)險(xiǎn)提示
批發(fā)價(jià)格存在階梯區(qū)間,需完整解析用于采購(gòu)量決策
4. 安全與合規(guī)
妥善保管 app_secret 和 access_token,避免泄露
生產(chǎn)環(huán)境建議部署在服務(wù)端,禁止客戶端直接調(diào)用
數(shù)據(jù)使用需遵守京東工業(yè)開放平臺(tái)的開發(fā)者協(xié)議
六、功能擴(kuò)展方向
商品對(duì)比工具:基于詳情數(shù)據(jù)實(shí)現(xiàn)多維度參數(shù)對(duì)比,輔助采購(gòu)決策
合規(guī)檢查系統(tǒng):自動(dòng)校驗(yàn)商品認(rèn)證是否滿足行業(yè)標(biāo)準(zhǔn)和項(xiàng)目要求
庫(kù)存預(yù)警功能:結(jié)合庫(kù)存數(shù)據(jù)和歷史采購(gòu)量,實(shí)現(xiàn)關(guān)鍵物料預(yù)警
價(jià)格趨勢(shì)分析:定期獲取價(jià)格數(shù)據(jù),分析價(jià)格波動(dòng)規(guī)律
通過本文提供的方案,開發(fā)者可以快速實(shí)現(xiàn)京東工業(yè)平臺(tái)商品詳情數(shù)據(jù)的對(duì)接,為工業(yè)采購(gòu)系統(tǒng)、供應(yīng)鏈管理工具等應(yīng)用提供精準(zhǔn)的數(shù)據(jù)支持。實(shí)際開發(fā)中,建議結(jié)合具體工業(yè)領(lǐng)域(如制造業(yè)、能源業(yè)等)的特性,進(jìn)一步優(yōu)化數(shù)據(jù)解析和應(yīng)用邏輯。????
審核編輯 黃宇
-
接口
+關(guān)注
關(guān)注
33文章
9525瀏覽量
157071 -
API
+關(guān)注
關(guān)注
2文章
2376瀏覽量
66806
發(fā)布評(píng)論請(qǐng)先 登錄
京東商品詳情API接口詳解:獲取商品標(biāo)題、價(jià)格、庫(kù)存等核心數(shù)據(jù)
施耐德平臺(tái)商品詳情API接口技術(shù)指南
調(diào)用野莓平臺(tái)商品詳情API接口實(shí)踐
標(biāo)題:技術(shù)實(shí)戰(zhàn) | 如何通過API接口高效獲取亞馬遜平臺(tái)商品詳情數(shù)據(jù)
京東平臺(tái)獲取商品詳情原數(shù)據(jù)API接口技術(shù)解析
如何通過API獲取1688平臺(tái)商品詳情
淘寶商品詳情API接口技術(shù)解析與實(shí)戰(zhàn)應(yīng)用
京東商品詳情接口實(shí)戰(zhàn)解析:從調(diào)用優(yōu)化到商業(yè)價(jià)值挖掘(附避坑代碼)
京東工業(yè)平臺(tái)商品詳情接口開發(fā)指南:工業(yè)級(jí)數(shù)據(jù)解析與實(shí)戰(zhàn)實(shí)現(xiàn)
評(píng)論