淘宝天猫 API Python 实战:搜索、SKU、问大家与评价

用淘宝天猫 API 搭商品研究流水线:销量与价格筛选、SKU 详情、问大家、评价分页、调用成本与安全归一化。

深色淘宝天猫研究控制台,把筛选搜索、SKU 详情、买家问答和评价证据连接起来

按销量排序很容易,解释这个榜单却很难。淘宝搜索可以按关键词、价格区间和是否天猫来缩小范围,但它不能自动证明最低价对应你要的 SKU,也不能证明评价里的体验属于同一变体。新上的淘宝 API 真正有用的方式,是把搜索、商品详情、问大家与评价通过商品 ID 和采集时间连接起来。

这篇文章给商品研究、货盘分析、竞品监测与购物 agent 的开发者一条完整 Python 路线。所有业务字段都来自 2026-11-01 的实测,并明确区分“端点文档保证的输入”和“这次响应里观察到的字段”。

先说结论

  • SandBase 当前列出 5 个淘宝端点,覆盖淘宝/天猫搜索、商品详情、店铺列表、问大家和商品评价。
  • 搜索文档化支持销量/价格排序、天猫筛选、价格区间与页码分页。
  • 11 月 1 日页面单价在 $0.0208–$0.0278/次之间。
  • 三类响应结构不同:搜索使用 model.itemList,详情使用 item / seller / delivery,评价使用 comments 与 hasNextPage。
  • 在 agent 读取数据前,先归一化并绑定 item ID、页码、请求、run id 与采集时间。

5 个端点组成一套商品研究工具箱

SandBase 淘宝 API 目录同时覆盖淘宝与天猫:

端点任务2026-11-01 页面价格
/v1/api/taobao/search/items关键词、排序、价格带、天猫筛选$0.0278
/v1/api/taobao/item/detail标题、图片、价格、SKU、配送、卖家$0.0208
/v1/api/taobao/shop-item-list指定店铺列表、排序与分页$0.0278
/v1/api/taobao/item/questions分页读取买家问答$0.0208
/v1/api/taobao/item/reviews按最新或默认顺序读取评价$0.0278

淘宝 API 目录列出搜索、详情、店铺、问答与评价端点 2026-11-01 的淘宝 API 目录快照。目录能证明路由可用,不能保证每个商品都有问答或评价数据。

淘宝提供底层市场数据,SandBase 提供统一 Bearer 认证、计费与完成态信封。outputs[0].data 里的内容仍是上游原始结构,必须防御式解析。

先把搜索问题写清楚

“找热门蓝牙耳机”不可复现;“找 100–300 元、非天猫、按销量排序的蓝牙耳机,再补前 10 个唯一商品 ID 的详情”才是一条可以审计的任务。

搜索端点文档化了以下输入:

  • 必填 keyword;
  • sort:_sale、_bid、bid 或 _coefp;
  • tmall:布尔值;
  • startPrice 与 endPrice:包含边界的字符串价格;
  • page:整数页码。

淘宝商品搜索端点展示排序、天猫与价格筛选 搜索端点提供 6 个输入,生产路由为 POST /v1/api/taobao/search/items。截图于 2026-11-01;页面没有解释的枚举语义不要自行猜测。

排序枚举很短。页面列出 _sale,但其他代码的精确定义如果没有文档或对照实验,就不应在 UI 里擅自翻译。生产系统只给已验证的含义加友好标签。

Python
import os
import requests

BASE = "https://api.sandbase.ai/v1/api/taobao"
HEADERS = {
    "Authorization": f"Bearer {os.environ['SANDBASE_API_KEY']}",
    "Content-Type": "application/json",
}

def call_taobao(path: str, payload: dict) -> dict:
    resp = requests.post(
        f"{BASE}/{path}", headers=HEADERS, json=payload, timeout=60
    )
    resp.raise_for_status()
    body = resp.json()
    outputs = body.get("outputs") or []
    if body.get("status") != "completed" or not outputs:
        raise RuntimeError(
            f"Taobao call did not complete: {body.get('status')} {body.get('error')}"
        )
    data = outputs[0].get("data")
    if not isinstance(data, dict):
        raise RuntimeError("Taobao call completed without an object payload")
    return {"run_id": body.get("id"), "data": data}

search = call_taobao("search/items", {
    "keyword": "蓝牙耳机",
    "page": 1,
    "sort": "_sale",
    "tmall": False,
})

下面的业务字段来自 2026-11-01(UTC+8)的真实调用,只是 observed-only,不是接口保证。搜索 run id 7f6d1a89-ab65-4147-875c-ff4001a08553 的顶层是 code、extraMap 和 model,本次商品列表位于 model.itemList。

这说明不能写一个“所有电商 API 都返回 products”的万能 helper。更稳的做法是单独做淘宝适配器,再输出稳定的内部记录:

Python
def iter_search_items(data: dict):
    model = data.get("model") or {}
    items = model.get("itemList") or []
    return items if isinstance(items, list) else []

def normalize_search_item(item: dict, run_id: str, request: dict) -> dict:
    return {
        "marketplace": "taobao",
        "item_id": item.get("itemId") or item.get("nid") or item.get("id"),
        "title": item.get("title"),
        "price_cny_raw": item.get("price"),
        "sales_raw": item.get("sold") or item.get("sales"),
        "shop_name": item.get("shopName") or item.get("nick"),
        "query": request,
        "observed_run_id": run_id,
        "observed_at": "2026-11-01",
    }

这里的候选字段只是兼容分支,不代表每次都会出现。应记录实际命中的路径,并对没有商品 ID 的记录报警。

用商品 ID 连接详情,不要拿标题 join

标题是营销文案,会变化,也常把多个兼容设备和促销词塞进一行。搜索与详情必须通过商品 ID 连接。

详情端点只接收一个 itemId。实测 run id 0668ca74-5f26-42b3-8ba5-d6d1d591619d 的业务负载由 item、seller、delivery 三部分组成。截短样本里,item 有标题和 5 张图片;delivery 出现了 area_id、delivery_fee、from、to。这些都只是本次观察。

Python
detail = call_taobao("item/detail", {"itemId": "920640959876"})

def normalize_detail(data: dict, run_id: str, requested_item_id: str) -> dict:
    item = data.get("item") or {}
    seller = data.get("seller") or {}
    delivery = data.get("delivery") or {}
    return {
        "marketplace": "taobao",
        "item_id": item.get("itemId") or requested_item_id,
        "title": item.get("title"),
        "images": (item.get("images") or [])[:8],
        "sku_source": item.get("skuBase"),
        "seller_id": seller.get("sellerId"),
        "shop_id": seller.get("shopId"),
        "delivery_fee_raw": delivery.get("delivery_fee"),
        "delivery_from": delivery.get("from"),
        "delivery_to": delivery.get("to"),
        "observed_run_id": run_id,
        "requested_item_id": requested_item_id,
    }

调用适配器时要传入同一个请求商品 ID。本次实测证据没有证明 item.itemId 一定存在,因此请求值是权威的 join-key fallback。搜索卡片价格不能直接与详情 SKU 价格比较。起售价、券后价、颜色/容量变体价格是不同的业务事实,必须先解析具体 SKU。

问大家和评价回答的是两种问题

问大家更像购买前的不确定性清单:兼容性、尺寸、配件、配送、使用方式。评价则是购买后的体验报告,同时带着抽样偏差、真伪与变体归属问题。两者不应混成一个“口碑分”。

问答端点接收 itemId 和整数 page;评价端点接收 itemId、整数 page,以及 feedbackdate 或 general 两种 orderType。分页只使用这些文档化参数。

淘宝商品评价端点展示 orderType 与 page 参数 评价路由支持最新/默认排序与整数页码。截图于 2026-11-01;用户评价是待核查证据,不是经过验证的商品事实。

评价 run id 23dc11fa-d632-47ea-b54a-8bb34a3333ba 中观察到 currentPageNum: 1、hasNextPage: true、total: 20000、comments 列表,以及“音质好”等关键词标签。这不保证其他商品有同样字段,也不能证明标签计数对应唯一、真实的购买者。

Python
reviews = call_taobao("item/reviews", {
    "itemId": "920640959876",
    "page": 1,
    "orderType": "feedbackdate",
})

def review_page(data: dict) -> dict:
    comments = data.get("comments") or []
    return {
        "page": data.get("currentPageNum"),
        "has_next": bool(data.get("hasNextPage")),
        "comments": [{
            "date": row.get("date"),
            "content": row.get("content"),
            "variant": row.get("auction"),
            "photos": row.get("photos") or [],
        } for row in comments],
    }

当 hasNextPage 为 false、下一页为空,或者达到事先声明的抽样预算时停止。接口还有下一页,不等于研究必须无限抓取。

3 种工作流的成本

以下计算使用 2026-11-01 的页面价格,之后可能变化。

1. 每日品类扫描

搜索 30 组关键词/价格带,补 40 个候选详情:30 × $0.0278 + 40 × $0.0208 = $1.666/次。连续 30 天为 $49.98。应缓存详情,只刷新仍在候选池中的商品。

2. 天猫货盘监测

搜索 20 条天猫限定查询,再为 10 个已知店铺各取一页:20 × $0.0278 + 10 × $0.0278 = $0.834/次。它反映观察到的货盘,不等于销量表现或确定库存。

3. 用户声音抽样

对 25 个商品分别取详情、1 页问答和 2 页评价:25 × ($0.0208 + $0.0208 + 2 × $0.0278) = $2.43。报告必须写清“每个商品抽 2 页”,不能泛化成完整评价语料。

Agent 应该看到什么

不要把整份电商原始响应丢给 agent,让它自己猜 join。给它一份有限的证据包:

JSON
{
  "item_id": "920640959876",
  "search_observation": {"query": "蓝牙耳机", "page": 1},
  "detail_observation": {"title": "...", "delivery_fee_raw": "..."},
  "review_sample": {"pages": 2, "latest_first": true},
  "limits": ["价格可能依赖 SKU", "评价样本不完整"]
}

然后只要求它完成窄任务:标记缺失证据、归纳已观察到的投诉主题、生成下一轮核查问题。不要让它从不完整公开数据里直接选“最佳商品”。

边界与限制

搜索排序只代表当时的平台响应;销量与评价数量可能经过上游格式化或聚合;天猫筛选改变候选池,但不自动证明商品真伪;评价样本可能偏向近期、激励性或特定变体;配送取决于目的地;SKU 价格要落到具体变体。最后,原始业务字段会变化,即使统一完成态信封没有变。

如果任务是批发 MOQ、阶梯价与供应商信号,应该看1688 Product Finder 指南。如果想看结构更简单的搜索—详情—评论链路,可以对照京东 API 实战。

FAQ

同时覆盖淘宝和天猫吗?

端点说明明确覆盖淘宝与天猫。搜索提供 tmall 布尔值做天猫限定,详情、问答、评价和店铺列表则通过对应商品或店铺 ID 工作。

需要单独申请淘宝开发者 key 吗?

这些端点通过 SandBase Bearer key 认证,页面没有要求额外的淘宝开发者 key。

评价排序怎么选?

研究目标是近期变化时用 feedbackdate;需要端点默认/综合顺序时用 general。必须保存选择,因为排序变化会改变证据集合。

能从销量排序算市场份额吗?

不能。排序搜索不是完整交易数据,只能用于发现和有边界的货盘比较,不能支撑严谨市场份额估算。

最后的判断

这 5 个淘宝端点已经覆盖一条严肃商品研究链:可控搜索、商品级详情、店铺货盘、购买前问答与购买后评价。它们的价值来自按 ID 与采集时间正确连接,而不是把所有原始字段一次性塞进 prompt。

把搜索、详情、问答和评价当成不同证据类型,分别归一化,保留请求与 run id,并让抽样边界对读者可见。这样购物或货盘 agent 才能辅助决策,而不会把不完整的公开市场数据冒充事实全貌。