Blog/开发者工具/

用一个 API 做小红书选品调研:一套实用工作流 | SandBase

搭一套小红书选品调研工作流:搜商品、读商品、拉它的评价——一把 SandBase key,不用小红书登录。

深色电影质感画面:小红书商品搜索解析成一个商品和它的评价,汇入 agent 核心

在小红书做选品调研,归根到底是三个动作:在一个品类里搜商品、打开一个商品、读买家怎么评价它。这篇教程用 SandBase 小红书 API 把这三个动作串成一套小红书选品调研工作流——仍需一把 SandBase key,但不用小红书登录,也不用爬虫。端点参考只保证响应信封(id、status、model、outputs[0].data);下面展示的业务字段是示例结构,不是保证的 schema,请以真实响应为准核对。

如果你想先看完整的端点全景,从 小红书公开数据 API hub 开始。这一篇是落地的工作流。

先说结论

  • 三步:search-products(发现)→ product-detail(商品)→ product-reviews(评价)。
  • 每次都是 POST /v1/api/xiaohongshu/<path>,一把 SANDBASE_API_KEY;响应共用 { id, status, model, outputs } 信封。
  • 搜索接一个 keyword;商品端点接一个你从搜索结果里提取的 sku_id。
  • 翻页是各端点自己的请求参数,不是把返回值再传回:搜索用 page(从 1 开始)加 search_id;product-reviews 用 sku_id,page 从 0 开始;product-recommendations 用 cursor_score。
  • 只是公开、只读数据;仍需一把 SandBase key,但你这边不用小红书登录,也不能发帖。

工作流全貌

步骤端点输入你拿到
1. 搜商品xiaohongshu/app-v2/search-productskeyword(+ page、search_id)商品搜索布局
2. 打开商品xiaohongshu/app-v2/product-detailsku_id结构化的商品详情
3. 读评价xiaohongshu/app-v2/product-reviewssku_id该商品的评价条目

SandBase 小红书端点参考,展示本工作流用到的商品搜索和详情端点 端点的 API 参考是每个参数名和响应路径的权威来源。

第 1 步 —— 搜商品

先写一个判 status 的帮助函数,再搜一个品类关键词:

import os
import requests

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


def call(path: str, payload: dict) -> dict:
    resp = requests.post(f"{BASE}/{path}", headers=HEADERS, json=payload, timeout=90)
    resp.raise_for_status()
    body = resp.json()
    if body.get("status") != "completed":
        raise RuntimeError(body.get("error", {}).get("message", "request did not complete"))
    return body["outputs"][0]["data"]


search = call("app-v2/search-products", {"keyword": "面膜", "page": 1})
# search 可能是一个结构化的商品布局(container/module);
# 看一份真实响应,提取你想要的 sku_id,若有 search_id 则一并读出
layout = search.get("data")
search_id = search.get("search_id")

search-products 的响应可能把一个结构化布局包在 data 下(含 container/module);具体结构是示例,依赖前先看一份真实响应。翻页是请求参数:传 page(从 1 开始),如果响应返回了 search_id,下一次请求就把它和 page 一起传回。迭代之前先提取你关心的商品的 sku_id——这个布局可能比一个扁平列表要丰富。

第 2 步 —— 打开商品

用从搜索里提取的 sku_id,读商品详情:

detail = call("app-v2/product-detail", {"sku_id": sku_id})
# detail 可能携带一个上游 { code, data, msg } 信封;
# 用 .get() 防御式访问——这些业务字段是示例结构,不是保证的 schema
if detail.get("code") == 0:
    product = detail.get("data")

product-detail 通常返回一个上游的 { code, data, msg, success } 风格信封;请把这些字段名当作示例结构,并以一份真实响应为准核对。用一个从搜索结果里提取的有效 sku_id——一个未知 id 往往会返回非零 code。读 detail.get("data") 之前先判 code == 0。

SandBase 小红书 product-detail API 参考,展示 sku_id 参数和响应 schema product-detail 在上游 data 对象下返回商品;先判 code。

第 3 步 —— 读评价

对同一个 sku_id 拉评价,衡量口碑:

reviews = call("app-v2/product-reviews", {"sku_id": sku_id, "page": 0})
# 用 .get() 防御式访问——这些业务字段是示例结构,不是保证的 schema
if reviews.get("code") == 0:
    items = reviews.get("data")

product-reviews 也接一个 sku_id,并用 page 翻页(这个端点的 page 从 0 开始)。它通常用一个上游的 { code, data, msg } 风格信封;只有外层信封(id、status、model、outputs[0].data)是保证的。下面是一个示例响应结构——请把字段名和数值当作示例,以一份真实响应为准核对:

{
  "id": "…",
  "status": "completed",
  "model": "xiaohongshu/app-v2/product-reviews",
  "outputs": [
    {
      "data": {
        "code": 0,
        "success": true,
        "data": { "…": "…" }
      }
    }
  ]
}

要一个汇总视角,xiaohongshu/app-v2/product-review-overview 对同一个 sku_id 返回一个评价概览(评分分布、好评率、评价标签)。

SandBase 小红书 product-reviews API 参考,展示 sku_id 参数和响应 schema product-reviews 在上游 data 对象下返回评价条目。

把它串起来

一次最小的选品调研过程长这样:

search = call("app-v2/search-products", {"keyword": "面膜"})
# 按 schema 从搜索布局里提取 sku_id
report = []

for sku_id in extract_sku_ids(search):  # extract_sku_ids: 你为搜索布局写的解析器
    detail = call("app-v2/product-detail", {"sku_id": sku_id})
    if detail.get("code") != 0:
        continue  # 跳过商品端点解析不出的 id
    overview = call("app-v2/product-review-overview", {"sku_id": sku_id})
    report.append({"sku_id": sku_id, "detail": detail.get("data"), "reviews": overview.get("data")})

extract_sku_ids 是伪代码——等你看过一份真实响应后,按实际的搜索布局去实现它。因为每次调用共用同一个信封和同一个 call 帮助函数,加重试或速率退避是一处改动的事。当你需要的不止这些读取时,查线上小红书列表找到合适的端点,接入前先确认它的参数。

处理粗糙的边角

  • 从搜索布局里提取 sku_id。 search-products 返回一个结构化的 container/module 布局,不是扁平列表——调商品端点之前,从真实响应里对准 sku id。
  • 对上游 code 分支。 商品端点透传一个 { code, data, msg } 信封;非零 code 表示 id 没解析出来。读 data 之前先判 code == 0。
  • 也对 status 分支。 failed 或 timeout 的请求带 error 而没有 outputs。call 帮助函数已经强制这一点。
  • 尊重速率限制。 作为客户端韧性措施,遇到 HTTP 429 这类瞬时错误时用退避重试。
  • 只是公开数据。 仍用一把 SandBase key 鉴权,但不用小红书登录、不发帖,也拿不到私密/仅账号可见的内容。

为什么在 API 层做这件事

你当然可以在浏览器里打开小红书手动抄商品数据,但那不 scale,也给不了你结构化数据。把这些调用排成定时任务,就把定性的浏览变成了可度量的信号:能按 sku_id 去重的商品、能做趋势的评价概览、以及能对比的品类。因为调用返回的是命名的 JSON 字段(在一个一致的信封后),每一轮都能干净地落进一张表,再和上一轮做 diff——某个关键词上新冒出的商品、评价口碑的变化,以及一个品类在推荐什么的变化。把评价文本变成洞察,是你在采集到的数据之上另跑的一个分析步骤。

组合这套工作流

同样的统一信封让它可组合。把品类关键词换成任意垂类,再加第四次读取——比如对一个 sku_id 调 product-recommendations(它用一个 cursor_score 请求参数翻页)——它就用同一个 call 帮助函数、同一套判 status 和 code 接进来。你也可以把漏斗放宽:一次过程里对多个品类关键词各跑一次 search-products,提取 sku id,先按评价概览排序,再拉完整评价,这样只对值得细看的商品花调用。因为这些读取共用一种结构,从一个快速脚本走到一个定时任务,基本上只是加个退避和一个存每轮结果的地方。

常见问题

我需要小红书登录或 OAuth 吗? 不需要。你用自己的 SANDBASE_API_KEY 向 SandBase 鉴权,搜商品、读商品以及拉评价,都不需要你这边有小红书账号或 OAuth。发起这些调用时你仍然要提供一把 SandBase API key。

这几个端点的翻页怎么做? 每个端点各有自己的请求参数——比如 product-reviews 接一个 page(从 0 开始),你每次调用递增它;而搜索的翻页值则带回到下一次 search-products 请求里。具体参数以各自的端点参考为准,迭代前先对着一份真实响应核对。

我能用这种方式读私密或仅账号可见的商品数据吗? 不能。这些是公开、只读的读取——拿不到私密或需登录才可见的数据。另外,端点参考只保证 { id, status, model, outputs } 这层信封(里面还套着上游的 { code, data, msg }),里面的业务字段会变,请以一份真实响应为准去对准。

下一步

你现在有了一套可复用的选品调研工作流,建立在公开、只读的调用上。