1688 / 京东 / 淘宝 item_get 返回字段逐个拆:三个平台的真实报文差在哪
跨平台做数据的人,八成的调试时间花在同一件事上:这个字段到底叫什么、是什么意思、单位是啥。这篇不讲架构,只把三个平台 item_get 的请求参数和返回报文摊开逐个字段过一遍,附一份可直接用的字段映射表。一、请求侧:一个网关跑三个平台
三个平台的调用形式完全统一,差异只在路径里的平台名:
https://api-gw.onebound.cn/{平台名}/{接口名}/平台名取 1688 / jd / taobao,接口名就是 item_get。公共参数三平台一致:
| 参数 | 必填 | 说明 | 取值 |
|---|---|---|---|
| key | 是 | 应用 key | 控制台分配 |
| secret | 是 | 应用密钥 | 控制台分配 |
| api_name | 否 | 接口名,部分调用方式需显式指定 | item_get |
| cache | 否 | 是否走缓存 | yes(默认)/ no |
| result_type | 否 | 返回格式 | json / xml / serialize |
| lang | 否 | 文案语言 | cn / en |
业务参数只有一个:num_iid(商品 ID)。所以最小的调用就是:
curl "https://api-gw.onebound.cn/1688/item_get/?key=你的key&secret=你的secret&num_iid=623415409661&cache=yes&result_type=json&lang=cn"
返回的外层结构三平台也是同一套,先认这几个字段再谈业务字段:
{ "item" : { "...商品字段..." } , "error" : "" , "error_code" : "0000" , "reason" : "" , "execution_time" : 0.318 , "request_id" : "b2f1c9d8..." }判成败只看 error_code:0000 是成功,2000 是搜索类接口的"无结果",4000 / 4001 / 4002 / 4017 是请求侧问题。这里有个和花费直接相关的细节值得记住:0000 和 2000 都计费,那四个 4 开头的错误码不计费。所以拿 2000 去轮询搜索等于持续花钱买空结果,而参数写错反倒不花钱——调试阶段真正该防的是前者。
二、1688:item 里最需要看清的字段
1688 的 item 返回字段多且杂,做成本核算和铺货真正高频用到的就这些:
| 字段 | 含义 | 实测注意点 |
|---|---|---|
| num_iid | 报价 ID | 唯一,建议加平台前缀后再当主键 |
| title | 标题 | 常带供应商自造的促销前缀 |
| price | 价格 | 区间字符串,如 "3.20-5.80",不是数字 |
| orginal_price | 原价 | 官方字段名就是拼错的,别"顺手改对" |
| min_num | 起订量 | 一件代发场景必须看,2 件起订的款不能按 1 件卖 |
| quantity | 库存 | 单位随类目变,可能是件/打/箱 |
| sold_quantity | 成交量 | 选品排序的主要依据 |
| seller_nick / company_name | 店铺 | 同一供应商可能有多个店铺 |
| pic_url / item_imgs | 主图/图集 | 图集是数组,铺货时按需截取 |
| skus.sku[] | 规格数组 | 真正的价格与库存都在这里 |
skus 要单独讲,因为它是唯一能拿到规格级价格的地方:
"skus" : { "sku" : [ { "sku_id" : "4902881234567" , "properties" : "1627207:28320;20509:28314" , "properties_name" : "颜色:黑色;尺码:L" , "quantity" : 812 , "price" : "3.20" , "orginal_price" : "4.50" } ] }properties 是平台的属性 ID 组合,properties_name 才是人看的文案。做规格库存判断必须用 sku[].quantity,不能用外层的 quantity——外层那个是全部规格的合计,拿它算可售量会把某个已断货的规格也放出去卖。
上面这些字段名和那个拼错的 orginal_price,我都核过好几遍。最快的核对方式不是翻文档,是在调试工具里打一份真实响应回来逐行对照,入口在 开放平台控制台,需要的自取。
三、京东:字段名相似,能力边界差很多
京东的 item_get 返回结构跟 1688 高度相似(price、title、pic_url、skus 都在),但有两个实操层面的差别。
一是 ID 前缀问题。 京东同一款商品在不同入口下可能返回纯数字 skuId,也可能带 J_ 前缀。落库前统一清洗,否则同一个款会存成两条记录。
二是不少字段要走别的接口。 京东 item_get 后台统计只有 78%,item_get_pro 也是 78%,item_history_price 75%——这条链路稳定性明显低于 1688。但它的 item_get_desc 有 98%,所以描述类字段从详情描述接口取,别指望主接口:
def jd_desc(num_iid, key, secret): r = call("jd", "item_get_desc", num_iid=num_iid, key=key, secret=secret) return r["item"]["description"] if r.get("error_code") == "0000" else None再补一条:京东的销量字段缺失很常见。想拿"卖得怎么样"这个信号,实际可用的替代是 item_review(评价接口,99%),用评价数近似。至于 item_search——后台统计只有 28%,别把主链路押在京东搜索上,它只适合做人工触发的补采。
四、淘宝:字段最全,但 item_get 的成功率是硬伤
淘宝返回的字段是三家里最完整的,问题出在成功率:item_get 和 item_get_pro 都只有 40%——每 5 次调用只有 2 次能拿到 item,另外 3 次落空。
对比之下淘宝其他接口反而很稳:item_link100%、item_search_shop_pro96%、item_password95%、item_search_img92%、item_search85%。
这个分布直接决定了策略:别用 item_get 硬扛,改成"列表接口铺量 + 详情接口补点"。
def tb_items(shop_id, page, key, secret): """用店铺商品接口取列表,96% 成功率,一次拿到一批商品的字段""" return call("taobao", "item_search_shop_pro", seller_id_or_nick=shop_id, page=page, key=key, secret=secret) def tb_detail(num_iid, key, secret, retry=2): """详情接口只对重点商品调用,拿不到就明示为空,不硬等""" for i in range(retry): r = call("taobao", "item_get", num_iid=num_iid, key=key, secret=secret) if r.get("error_code") == "0000" and r.get("item"): return r["item"] return None # 40% 的接口,拿不到是常态,别让它阻塞任务五、字段映射表:让三个报文落进同一张表
差异认清了,落地就简单。写成声明式映射,新增平台只加一段配置:
FIELD_MAP = { "1688": {"id": "num_iid", "price": "price", "origin": "orginal_price", "min_num": "min_num", "stock": "quantity", "sold": "sold_quantity", "seller": "seller_nick", "pic": "pic_url"}, "jd": {"id": "num_iid", "price": "price", "origin": "orginal_price", "min_num": "min_num", "stock": "quantity", "sold": "sold_quantity", "seller": "shop_name", "pic": "pic_url"}, "taobao": {"id": "num_iid", "price": "price", "origin": "orginal_price", "min_num": "min_num", "stock": "quantity", "sold": "sold_quantity", "seller": "nick", "pic": "pic_url"}, } def parse_price(raw): """'3.20-5.80' / '3.50' / '面议' 都要接得住""" if raw is None: return None, None nums = re.findall(r"\d+(?:\.\d+)?", str(raw)) if not nums: return None, None # 面议不能当 0,否则定价直接崩 vals = [Decimal(n) for n in nums] return min(vals), max(vals) # 一价时 min == maxparse_price 那两行是我改得最多的地方:早期版本直接 float(item["price"]),碰上区间价抛异常、碰上"面议"返回 0,定价模块跟着一起错。归一化函数的原则是"不确定就给 None,不要给默认值",让空值在后续校验里暴露出来,比默默按 0 元算安全得多。
六、收尾
字段这东西,看文档不如看报文。另外一个建议:把原始 item JSON 整段存进 raw_json 列——归一化一定会漏字段,能回捞历史报文比重新调接口便宜得多,毕竟成功和"无结果"都是要计费的。


