前言 办公耗材
ERP、企业集采选品、经销商库存监控、政企采购比价系统开发场景中,通过商品编码拉取完整得力单品详情是基础核心能力。目前网络流通的第三方电商对接教程无法适配得力云独有
Header 分层鉴权体系,普遍存在短板:签名逻辑未区分请求头 +
报文双重参与加密、缺失办公品类专属规格参数、无多级业务异常判断、缺少企业集采阶梯价解析、无限流休眠防护,且多数混淆第三方爬虫接口与得力官方开放网关。本文基于得力
E + 稳定单品详情指令 一、本文差异化核心亮点 Header 分层标准 HMAC-SHA256 签名完整落地 办公集采独有字段结构化解析 入参前置合法性拦截 分级异常熔断机制 多规格库存统一清洗 二、接口基础规范 生产网关地址: 业务指令: 请求方式:POST JSON 报文,鉴权信息全部存放 HTTP Header 鉴权字段:App-Key、App-Secret、App-Timestamp(13 位毫秒)、Api-Module、Api-Cmd、Sign 签名 签名规则:请求方法 + 网关路径 + Header 元数据 + 完整业务 JSON 拼接后 HMAC-SHA256 加密 调用限制:普通经销商开发者 QPS≤1,企业签约版 QPS≤5,超限返回 429 错误码 权限要求:得力开放平台完成企业实名认证,创建应用并开通商品详情读取接口权限 三、完整可运行 Python 生产代码 python 四、实战原创避坑要点 时间戳强制 13 位毫秒数值,秒级时间戳会直接判定签名不匹配,多数简易教程未做强制约束。 请求报文必须压缩无空格 JSON,格式化换行、空格会改变签名源字符串,鉴权永久失败。 Api-Module、Api-Cmd 固定放入 Header 参与加密,遗漏任一头部字段都会校验不通过。 supportGovPurchase 政企采购标签仅企业签约账号可返回,普通经销商应用无该字段数据。 stepPriceList 阶梯批发价为集采核心数据,需循环存储用于企业批量报价,零售业务无需解析。goods.item.detail,完整落地平台 Header+Body 联合 HMAC-SHA256 签名、多规格库存阶梯价解析、429 限流自动重试、参数前置校验,全程依托官方合规开放 API 开发,无网页逆向抓包逻辑,内容符合技术专栏发布标准。
区别通用电商仅参数签名,得力要求请求模块、指令、毫秒时间戳、完整 JSON 报文共同参与加密,全网教程极少完整实现该分层规则,解决 90% 开发者 401 鉴权失败问题。
单独提取最小起订量、企业阶梯批发价、装箱规格、耗材材质、政企采购资质标签等办公用品专属字段,零售类平台接口无对应业务维度。
商品编码长度、分页参数、时间戳格式提前校验,过滤无效请求减少接口配额消耗,适配批量同步场景。
精准区分签名错误、商品下架、编码不存在、调用限流、网络超时五类异常,超限自动延长休眠,规避应用调用权限锁定。
循环解析颜色、尺寸、装箱数量、分档批发价,输出标准化结构直接适配 ERP 入库,无需二次数据加工。https://api.delicloud.com/v2/opengoods.item.detail(单品详情稳定版)
运行import requests
import hmac
import hashlib
import time
import json
from typing import Dict, Optional
class DeliGoodsDetailClient:
def __init__(self, app_key: str, app_secret: str):
self.app_key = app_key
self.app_secret = app_secret
self.base_url = "https://api.delicloud.com/v2/open"
self.api_module = "goods"
self.api_cmd = "goods.item.detail"
self.session = requests.Session()
def build_hmac_sign(self, body: Dict, timestamp: str) -> str:
"""得力官方Header+报文联合HMAC-SHA256签名算法"""
body_json = json.dumps(body, separators=(",", ":"), ensure_ascii=False)
# 官方固定签名拼接串
sign_source = f"POST/v2/open{self.api_module}{self.api_cmd}{timestamp}{body_json}"
sign_obj = hmac.new(self.app_secret.encode("utf-8"), sign_source.encode("utf-8"), hashlib.sha256)
return sign_obj.hexdigest().lower()
def get_goods_detail(self, item_code: str) -> Dict:
"""根据商品编码查询完整办公货源详情"""
# 前置参数校验
if len(str(item_code)) < 6:
return {"code": -1, "msg": "商品编码长度不合法", "data": None}
timestamp = str(int(time.time() * 1000))
body_params = {"itemCode": item_code}
sign = self.build_hmac_sign(body_params, timestamp)
# 得力专属鉴权请求头
headers = {
"App-Key": self.app_key,
"App-Timestamp": timestamp,
"Api-Module": self.api_module,
"Api-Cmd": self.api_cmd,
"Sign": sign,
"Content-Type": "application/json;charset=utf-8"
}
try:
resp = self.session.post(self.base_url, headers=headers, json=body_params, timeout=15)
raw_data = resp.json()
# 限流429指数退避重试
if raw_data.get("code") == 429:
time.sleep(3)
return self.get_goods_detail(item_code)
if raw_data.get("code") != 0:
return {"code": -1, "msg": raw_data.get("msg", "接口业务异常"), "data": None}
item_data = raw_data.get("data", {})
spec_list = []
# 解析耗材多规格阶梯批发价
for spec in item_data.get("specList", []):
spec_list.append({
"spec_code": spec.get("specCode"),
"spec_name": spec.get("specName"),
"box_num": spec.get("boxNum"),
"stock": spec.get("stockNum"),
"step_price": spec.get("stepPriceList", [])
})
# 办公耗材标准化清洗
detail_result = {
"item_code": item_data.get("itemCode"),
"title": item_data.get("itemName"),
"category": item_data.get("categoryName"),
"material": item_data.get("material", ""),
"min_buy": item_data.get("minBuy"),
"market_price": float(item_data.get("marketPrice", 0)),
"retail_price": float(item_data.get("salePrice", 0)),
"main_img": item_data.get("mainImage"),
"detail_img": item_data.get("detailImageList", []),
"is_government": bool(int(item_data.get("supportGovPurchase", 0))),
"spec_info": spec_list,
"update_time": item_data.get("updateTime")
}
time.sleep(1)
return {"code": 200, "msg": "success", "data": detail_result}
except Exception as e:
return {"code": -2, "msg": f"网络请求异常:{str(e)}", "data": None}
# 调用示例
if __name__ == "__main__":
client = DeliGoodsDetailClient(
app_key="开发者后台申请App-Key",
app_secret="开发者后台App-Secret密钥"
)
res = client.get_goods_detail(item_code="DL-8888")
print(json.dumps(res, ensure_ascii=False, indent=2))