×

《淘宝商品API:taobao.item.get 与 taobao.item.seller.get 的权限边界与字段缺失踩坑》(附 Python 源码)

万邦科技Lex 万邦科技Lex 发表于2026-10-12 10:26:25 浏览28 评论0

抢沙发发表评论

《淘宝商品API:taobao.item.get 与 taobao.item.seller.get 的权限边界与字段缺失踩坑》(附 Python 源码)

先拍结论:
taobao.item.get = 商品公开/半公开视图(无 session 拿公开字段,有 session 拿更多);
taobao.item.seller.get = 卖家自有商品后台视图(必须卖家 session,拿 SKU 库存/属性/详情/店铺内类目等经营数据)。
两者不是“同一个接口的两个名字”,而是“买家/竞品视角” vs “店主/ERP 视角”。
字段缺失 90% 不是接口坏了,而是:没授权、fields 没要、类目无此字段、私密字段不返回、sold_quantity 本来就不给。

一、权限边界一张表

维度
taobao.item.get
taobao.item.seller.get
视角
商品详情(买家/竞品/选品)
卖家自有商品(店铺后台)
是否要卖家 session
否(公开字段);传 session 可扩字段
必须 session(卖家授权)
能查谁的商品
任意淘宝/天猫商品(权限允许时)
只能查授权店铺自己的商品
典型用途
竞品监控、铺货源、价格/主图/SKU 公开信息
ERP 商品同步、库存、SKU 编码、详情 HTML、店铺类目
私密字段
拿不到(利润/采购价/全量私域属性)
能拿更多,但平台控字段
下架/仓库商品
通常查不到或返回空
能查(配合 items.inventory.get 找 ID)
常见误用
拿它当“店铺后台全量接口”
拿它查竞品/别的店 → 空/权限错
官方口径很直白:
taobao.item.get “卖家未登录时只能获得这个商品的公开数据,卖家登录后可以获取商品的所有数据”;taobao.item.seller.get 走 session=xxx 查本店商品。

二、字段缺失的 6 个真因(别先怀疑 SDK)

1️⃣ fields 没传 / 传了不存在字段

淘宝是“你问什么给什么”:
fields=num_iid,title,price
→ 只返回这 3 个;skus / desc / item_imgs 根本不在响应里
传不存在字段会报 Invalid Parameter。
✅ 按场景维护 fields 白名单。

2️⃣ 没 session → 公开层自动砍字段

taobao.item.get 无 session:
  • 给:title / pic_url / price / cid / nick / detail_url

  • 不给/不稳定:详细 SKU 库存、私域属性、店铺内类目、采购底价、部分销量

有 session:
  • 返回集合扩大,但是否返回仍看应用权限包


3️⃣ sold_quantity 官方就不返回

taobao.item.get 文档明确:Item 结构体所有字段可返回,除 sold_quantity。
你还去 item["sold_quantity"] 取值 = 永远 None。
✅ 销量要么用 taobao.items.search 的搜索层字段,要么接受“平台不给你真实已售”。

4️⃣ 类目/商品类型不支持该字段

  • 虚拟商品(话费/点卡):库存/SKU 语义不同

  • 秒杀商品:编辑类字段受限

  • 3D 商品 / 淘1站 / 秒杀标记:部分字段有特殊含义或不可改

✅ 解析前先读 type / approve_status / second_kill / is_3D。

5️⃣ 下架/删除/违规商品

  • taobao.item.get 查别人下架商品 → 空 / invalid

  • taobao.item.seller.get 才能查自己仓库里商品,但也要先从 items.inventory.get 拿到 num_iid

✅ 全店商品 = items.onsale.get + items.inventory.get + 按 id 补 item.seller.get。

6️⃣ 应用没签“商品读”/“增值”权限

淘宝是最小授权:
  • 基础商品读:title/price/pic 可能给

  • SKU 库存、详情 HTML、视频、属性全景:要对应权限包

  • CRM/会员/转化/流量:增值,塔内+签约

看到:
{"error_response":{"code":21,"msg":"Check App Permission Fail"}}
不是限流,是AppKey 没这个字段的权限。

三、生产向:两个接口的“职责分离”

竞品/选品/铺货源
   └─ taobao.item.get(num_iid + 公开 fields)
      ├─ title / pic_url / price / cid / props_name
      ├─ skus(公开部分)
      └─ 不依赖卖家 session

自有店铺 ERP 同步
   └─ items.onsale.get / items.inventory.get (拿 num_iid 列表)
        └─ taobao.item.seller.get(session=卖家token)
             ├─ skus.num / outer_id / barcode
             ├─ desc / item_imgs / video
             ├─ seller_cids / input_pids / input_str
             └─ 库存/规格/店铺内类目
规则:
用 item.get 做“全网商品理解”,用 item.seller.get 做“本店商品资产”。
把 item.seller.get 拿到的 SKU 编码/库存,当成 ERP 主数据;把 item.get 拿到的价格/主图,当成“前台展示/铺货源”。

四、Python:统一商品适配器

# top/item_adapter.py
from dataclasses import dataclass, field
from typing import Optional


@dataclass
class TopItemView:
    num_iid: str
    title: Optional[str] = None
    price: Optional[float] = None
    pic_url: Optional[str] = None
    cid: Optional[str] = None
    nick: Optional[str] = None
    skus: list[dict] = field(default_factory=list)
    desc: Optional[str] = None
    outer_id: Optional[str] = None
    stock_total: Optional[int] = None
    is_owner_view: bool = False
    missing_fields: list[str] = field(default_factory=list)
    raw: dict = field(default_factory=dict)


class TopItemClient:
    PUBLIC_FIELDS = [
        "num_iid", "title", "price", "pic_url", "cid", "nick",
        "detail_url", "item_imgs", "props_name", "skus",
    ]
    OWNER_FIELDS = [
        "num_iid", "title", "price", "pic_url", "cid",
        "skus", "desc", "item_imgs", "video",
        "seller_cids", "input_pids", "input_str", "outer_id",
        "num", "modified",
    ]

    def __init__(self, top_client):
        |  # top_client.execute(method, params)
        self.top = top_client

    def get_public_item(self, num_iid: str) -> TopItemView:
        resp = self.top.execute("taobao.item.get", {
            "num_iid": num_iid,
            "fields": ",".join(self.PUBLIC_FIELDS),
        })
        item = (resp.get("item_get_response") or {}).get("item") or {}
        return self._normalize(item, owner=False)

    def get_owner_item(self, num_iid: str, seller_session: str) -> TopItemView:
        resp = self.top.execute("taobao.item.seller.get", {
            "num_iid": num_iid,
            "fields": ",".join(self.OWNER_FIELDS),
            "session": seller_session,
        })
        item = (resp.get("item_seller_get_response") or {}).get("item") or {}
        return self._normalize(item, owner=True)

    def _normalize(self, item: dict, owner: bool) -> TopItemView:
        want = set(self.OWNER_FIELDS if owner else self.PUBLIC_FIELDS)
        got = set(k for k, v in item.items() if v not in (None, "", [], {}))
        view = TopItemView(
            num_iid=str(item.get("num_iid")),
            title=item.get("title"),
            price=_f(item.get("price")),
            pic_url=item.get("pic_url"),
            cid=item.get("cid"),
            nick=item.get("nick"),
            skus=item.get("skus", {}).get("sku", []) if isinstance(item.get("skus"), dict) else item.get("skus", []),
            desc=item.get("desc"),
            outer_id=item.get("outer_id"),
            stock_total=_i(item.get("num")),
            is_owner_view=owner,
            missing_fields=sorted(want - got),
            raw=item,
        )
        return view
消费侧铁律:
view = client.get_public_item(num_iid)
if "skus" in view.missing_fields and not view.is_owner_view:
    # 不是接口挂了:公开视图本来可能不给完整库存
    fallback_to_owner_or_skip(view)

五、SKU 解析:淘宝 SKU 是“属性组合”,不是“尺寸+颜色”两列

def parse_taobao_skus(skus: list[dict]):
    out = []
    for s in skus:
        out.append({
            "sku_id": s.get("sku_id"),
            "outer_id": s.get("outer_id"),
            "barcode": s.get("barcode"),
            "price": _f(s.get("price")),
            "quantity": _i(s.get("quantity")),
            # properties_name: "1627207:28332:颜色:黑;20509:28381:尺码:XL"
            "attrs": _parse_props(s.get("properties_name", "")),
        })
    return out

# 封装好API供应商demo url=https://console.open.onebound.cn/console/?i=Lex
def _parse_props(text: str):
    attrs = {}
    for seg in text.split(";"):
        seg = seg.strip()
        if not seg:
            continue
        # pid:vid:name:value
        parts = seg.split(":")
        if len(parts) >= 4:
            _, _, name, value = parts[0], parts[1], parts[2], parts[3]
            attrs[name] = value
    return attrs
跨平台映射时:别用“颜色/尺寸”硬字段,用 attrs 字典 + SKU 指纹,不然铺到 Mercari/闲鱼/1688 全串。

六、字段缺失兜底策略(ERP 必须写)

def safe_publish_payload(view: TopItemView) -> dict:
    payload = {
        "source": "taobao",
        "num_iid": view.num_iid,
        "title": view.title or "未授权标题",
        "price": view.price,
        "images": [view.pic_url] if view.pic_url else [],
    }

    if not view.skus:
        payload["warn"] = "no_sku:item.get 无 session 或字段未授权"
    if view.desc is None:
        payload["warn"] = (payload.get("warn") or "") + ";desc_not_granted"
    if view.outer_id is None and view.is_owner_view:
        payload["warn"] = (payload.get("warn") or "") + ";outer_id_missing"

    # 公开视图禁止声称“我有完整库存”
    if not view.is_owner_view:
        payload["inventory_trusted"] = False
    else:
        payload["inventory_trusted"] = view.stock_total is not None
    return payload

七、限流与调用策略

  • taobao.item.get:公开采集接口,QPS 低、日额度低、大促限流狠

  • taobao.item.seller.get:按卖家 session 再叠一层用户级限流

  • 列表先拿 ID,详情后补;别用 item 接口硬翻全店

  • 字段按需要,别 fields=*(淘宝也没有真 *,但乱传字段会错)

BUCKET_ITEM_GET = TokenBucket(rate=5)        # 官方可能 2~10,留余量
BUCKET_SELLER_GET = TokenBucket(rate=8)      # 本店私有接口别猛打

def sync_owner_catalog(seller_session, client):
    ids = []
    ids += list_onsale_ids()      # taobao.items.onsale.get
    ids += list_inventory_ids()   # taobao.items.inventory.get
    for num_iid in ids:
        BUCKET_SELLER_GET.acquire()
        view = client.get_owner_item(num_iid, seller_session)
        upsert_catalog(view)

八、和前几篇收口

  • 1688 商品 API:offer/item/product/sku 是供货视角,retailPrice/consignPrice 是分销价

  • 淘宝 TOP 认证限流:item.get 走应用凭证,item.seller.get 必须卖家 session

  • 1688 图片空间:淘宝 pic_url 同理——img.alicdn.com 别直链,转存

  • 消息服务:商品变更消息只触发,真相用 item.seller.get 拉

  • 本文:

    item.get 回答“这个商品对外长啥样”,
    item.seller.get 回答“我店里这个商品到底有哪些 SKU/库存/属性”。
    用错接口 = 竞品监控拿不到库存,店铺 ERP 拿不到竞品。

九、一句话收口

淘宝商品 API 的坑不在签名,在视角:
无 session 的 item.get 永远只是“橱窗”;
有 session 的 item.seller.get 才是“仓库和货架”。
字段没了先问三句——
“你传 fields 了吗?你带 session 了吗?这个字段平台本来给吗?”
三句答完,80% 的“接口坏了”都会变成“权限模型没设计对”。


群贤毕至

访客