淘宝/天猫 item_get(对应官方 taobao.item.get)是获取商品详情的核心接口,但新手常因 num_iid 无效、签名错误等问题无法获取数据。本文将详解接口字段、常见报错(特别是 invalid num_iid)的根源,并提供可直接运行的 Python 源码。
一、 接口基础与 num_iid 解析
- 接口核心参数
item_get 用于获取商品标题、价格、销量、SKU 等全量信息。其核心请求参数如下:
参数 是否必填 说明
method 是 固定为 taobao.item.get
num_iid 是 商品数字 ID(注意:不是 iid 字符串)
fields 是 需返回的字段,如 title,price,pic_url
num_iid 的正确获取方式:
从商品详情页 URL 中提取纯数字部分:
• 淘宝:https://item.taobao.com/item.htm?id=**674904123402**
• 天猫:https://detail.tmall.com/item.htm?id=**674904123402**
• 注意:必须是 11-13 位的纯数字,不能包含字母或特殊字符。
- 核心响应字段详解
接口返回的 JSON 结构通常包含 item_get_response -> item 对象。以下是业务开发中最常用的字段:
字段 类型 说明
num_iid Bigint 商品唯一 ID
title String 商品标题
price String 商品价格(原价)
promotion_price String 促销价(如有)
pic_url String 商品主图 URL
detail_url String 商品详情页链接
sold_quantity Integer 总销量(注意:部分类目可能受限)
num Integer 库存数量
approve_status String 商品状态:onsale(在售)/ instock(仓库中)
sku List SKU 列表(包含规格、价格、库存)
props_name String 商品属性(如 "品牌:XX;材质:XX")
二、 高频报错与解决方案(重点:invalid num_iid)
- invalid num_iid / ITEM_NOT_FOUND(错误码 27)
这是最常见的报错,通常表现为 isv.item-not-exist:invalid-numIid-or-iid 或 ITEM_NOT_FOUND。
原因分析:
- ID 格式错误:num_iid 包含空格、字母或非数字字符。
- 商品不存在:商品已下架、删除、或进入历史库(违规或被屏蔽)。
- 权限不足:该商品属于其他卖家,且你的应用未获得相应授权。
解决方案:
• 校验 ID:确保 num_iid 为 11-13 位纯数字。
• 状态检查:通过 taobao.items.onsale.get 接口获取你店铺的在售商品 ID,确保 ID 来源正确。
• 业务容错:一旦报此错误,应在本地标记该商品为“失效”,避免重复请求。
- 签名错误(错误码 15)
原因:签名(sign)计算错误。
解决:
• 严格按照 ASCII 码升序 排序所有参数(包括公共参数)。
• 确保 AppSecret 正确,且参数值经过 URL 编码(特别是含空格或中文时)。
- 频率限制(错误码 429)
原因:QPS(每秒请求数)超限。
解决:
• 免费版通常限制为 5 次/秒,需在代码中加入 time.sleep(0.2) 控制节奏。
• 使用缓存机制,避免对同一商品重复调用。
三、 Python 实战源码(含签名生成与错误处理)
以下代码实现了完整的淘宝 item_get 接口调用,包含签名生成、参数校验和常见错误处理。
import hashlib
import time
import requests
import urllib.parse
from typing import Dict, Optional
封装好API供应商demo url=https://console.open.onebound.cn/console/?i=Lex
class TaobaoItemAPI:
"""淘宝商品API客户端(支持item_get)"""
def __init__(self, app_key: str, app_secret: str):
self.app_key = app_key
self.app_secret = app_secret
self.gateway = "https://eco.taobao.com/router/rest" # 正式环境网关
def _generate_sign(self, params: Dict) -> str:
"""生成淘宝API签名(MD5加密)"""
# 1. 按参数名ASCII升序排序
sorted_params = sorted(params.items())
# 2. 拼接键值对
query_string = ''.join([f'{k}{v}' for k, v in sorted_params])
# 3. 前后拼接AppSecret并MD5
sign_str = self.app_secret + query_string + self.app_secret
return hashlib.md5(sign_str.encode('utf-8')).hexdigest().upper()
def _validate_num_iid(self, num_iid: str) -> bool:
"""校验num_iid格式(11-13位纯数字)"""
if not num_iid or not num_iid.isdigit() or len(num_iid) < 11 or len(num_iid) > 13:
raise ValueError(f"❌ 无效num_iid: {num_iid},必须为11-13位纯数字")
return True
def item_get(self, num_iid: str, fields: str = "num_iid,title,price,pic_url,detail_url,sold_quantity") -> Optional[Dict]:
"""
调用taobao.item.get接口获取商品详情
Args:
num_iid: 商品数字ID(从URL中获取)
fields: 需要返回的字段,逗号分隔
Returns:
dict: 商品信息字典,失败返回None
"""
# 1. 参数校验
self._validate_num_iid(num_iid)
# 2. 构建公共参数
timestamp = time.strftime("%Y-%m-%d %H:%M:%S")
base_params = {
"app_key": self.app_key,
"method": "taobao.item.get",
"timestamp": timestamp,
"format": "json",
"v": "2.0",
"sign_method": "md5",
"num_iid": num_iid,
"fields": fields
}
# 3. 生成签名并添加
base_params["sign"] = self._generate_sign(base_params)
try:
# 4. 发送GET请求
response = requests.get(self.gateway, params=base_params, timeout=10)
response.raise_for_status()
result = response.json()
# 5. 解析响应
if "item_get_response" in result:
item_data = result["item_get_response"].get("item", {})
print(f"✅ 获取商品成功: {item_data.get('title', 'N/A')}")
return item_data
else:
# 处理错误响应
error = result.get("error_response", {})
error_code = error.get("code")
error_msg = error.get("msg", "未知错误")
if error_code in [27, "27"] or "invalid num_iid" in error_msg.lower():
print(f"❌ 商品不存在或ID无效 (Code: {error_code}): {error_msg}")
elif error_code in [15, "15"]:
print(f"❌ 签名错误 (Code: {error_code}): 请检查AppSecret和参数排序")
elif error_code in [429, "429"]:
print(f"⏳ 频率超限 (Code: {error_code}): 请降低调用频率")
else:
print(f"⚠️ 接口调用失败 (Code: {error_code}): {error_msg}")
return None
except requests.exceptions.RequestException as e:
print(f"🌐 网络请求失败: {e}")
return None
except ValueError as e:
print(f"📦 JSON解析失败: {e}")
return None
==================== 使用示例 ====================
if name == "main":
# 请替换为你的实际密钥(从淘宝开放平台获取)
APP_KEY = "你的AppKey"
APP_SECRET = "你的AppSecret"
# 示例商品ID(请替换为真实的在售商品ID)
SAMPLE_NUM_IID = "674904123402" # 示例ID,需替换
# 封装好API供应商demo url=https://console.open.onebound.cn/console/?i=Lex
# 初始化客户端
client = TaobaoItemAPI(APP_KEY, APP_SECRET)
# 调用item_get接口
item = client.item_get(SAMPLE_NUM_IID)
# 打印结果
if item:
print("📦 商品详情:")
print(f" 商品ID: {item.get('num_iid')}")
print(f" 标题: {item.get('title')}")
print(f" 价格: {item.get('price')}")
print(f" 销量: {item.get('sold_quantity', 0)}")
print(f" 详情页: {item.get('detail_url')}")
else:
print("💥 获取商品详情失败,请检查上述错误信息。")
四、 生产环境最佳实践
ID 来源管理:
◦ 不要依赖用户输入的 URL 直接提取 num_iid,应通过 taobao.items.onsale.get(获取在售商品)或 taobao.item.search(搜索商品)接口获取权威 ID。错误重试机制:
◦ 对于网络错误(如超时)可重试 1-2 次,但对于 invalid num_iid 或 ITEM_NOT_FOUND 绝对不要重试,直接标记为失效。数据缓存:
◦ 商品基础信息(如标题、主图)变化频率低,可缓存 10-30 分钟,减少 API 调用压力。
💡 总结
item_get 接口的核心在于 num_iid 的准确性和签名的正确性。遇到 invalid num_iid 错误时,首要任务是检查 ID 格式和来源,而非盲目重试。上述 Python 代码提供了完整的签名生成和错误处理逻辑,可直接用于业务开发。
互动话题:
你在调用淘宝 API 时还遇到过哪些奇葩报错(如 subcode 错误)?评论区分享你的踩坑经历!