小红书蒲公英 API 教程:达人筛选、合作报价与粉丝画像
通过 Just One API 按粉丝数量筛选小红书蒲公英达人,获取达人资料、图文与视频合作报价及粉丝画像。包含保留空值、分页去重和保存候选名单的 Python 示例。
从粉丝范围筛选到达人候选名单
准备小红书达人合作时,通常需要先找出符合规模要求的账号,再检查报价和受众是否合适。Just One API 的小红书蒲公英接口可以把这几个步骤串起来:搜索达人,获取资料,再获取粉丝画像。
本教程以粉丝数 1 万到 10 万的达人为例,最多读取两页搜索结果,为其中三位达人保存资料、报价和画像。这个范围用于演示筛选流程,你可以按项目要求调整。输出是待评估的候选名单,合作决策仍需结合内容质量、报价可见性和业务需求。
如果目标是小红书笔记正文或评论,请先看小红书与蒲公英的数据范围区别。这篇教程聚焦蒲公英的达人营销数据。
注册、获取 Token 并在线测试
注册 Just One API 后获取 API Token,即可通过在线接口文档免费测试。一个 Token 可用于多个平台接口,后续按实际调用量付费;各接口的可用权限和免费测试次数以账户显示为准。
先打开达人搜索 V1,填写 Token、粉丝上下限和页码,检查返回体的业务 code 是否为 0。HTTP 请求成功与业务成功要分别判断。
教程使用三个 GET 接口,均通过查询参数 token 鉴权。脚本从环境变量读取 Token,不在源代码中保存真实值,也不输出带 Token 的完整请求地址。
第一步:筛选达人并保留 userId
搜索接口的路径为 /api/xiaohongshu-pgy/api/solar/cooperator/blogger/v2/v1。本例设置以下参数:
fansNumberLower=10000、fansNumberUpper=100000:筛选粉丝数量范围。sort=FANS:按粉丝数降序;需要平台智能排序时使用DEFAULT。page=1:从第一页开始,下一页递增页码。
当前公开响应样例把达人列表放在 data.kols,每条记录的 userId 用于后续查询。脚本按这个 ID 去重,再选取少量达人查询详情。
搜索结果中的 total 可以辅助了解平台返回的结果规模,但不应直接当作全平台达人总数。示例设置最多两页,并在空列表或整页没有新增 ID 时停止,防止重复采集。修改筛选条件后,应从第一页重新开始。
第二步:读取达人资料和合作报价
把搜索得到的 userId 传给达人资料 V1。当前公开样例中的资料字段包括 data.name、data.fansCount、data.picturePrice、data.videoPrice 和 data.showPrice。
其中图文与视频报价可能为空。报价为 null 表示本次没有拿到对应值,不能填成 0,也不能据此认定达人免费合作。showPrice 与原始报价一起保留,便于之后判断显示状态。进入预算比较前,还要确认当前字段的单位、合作形式和适用条件。
脚本会保存完整资料响应,同时生成便于查看的 shortlist.json。搜索页与资料页可能在不同时间返回数据,出现差异时保留两个原始响应,并记录采集时间,避免静默覆盖。
第三步:获取粉丝画像
使用同一个 userId 调用粉丝分布 V1。当前公开样例包含这些字段:
data.ages:年龄分组,其中包含group和percent。data.gender:性别分布。data.provinces、data.cities:地域分布。data.interests、data.devices:兴趣与设备相关分布。data.dateKey:画像数据对应的日期标记。
这些分布适合辅助判断候选达人是否接近目标受众。做报表前先确认各字段的单位与分母,避免把比例值统一乘以 100,或把某个分组缺失理解为零。示例保留整个画像对象,并把 dateKey 写进候选名单,便于核对数据时点。
Python 示例:保存候选名单、资料和画像
安装依赖并设置环境变量。把 your_token 替换成自己的 Token;下面的命令适用于 macOS 或 Linux 终端。
python3 -m pip install requests
export JUSTONEAPI_TOKEN='your_token'保存下方代码为 pugongying_sample.py,运行 python3 pugongying_sample.py。最多请求两页搜索结果,再查询三位达人的资料与画像,总计不超过 8 次 API 请求;提前结束或出错时次数更少。这是示例的采样上限,不是接口配额。
import json
import os
from datetime import datetime, timezone
from pathlib import Path
import requests
BASE_URL = "https://api.justoneapi.com"
TOKEN = os.environ.get("JUSTONEAPI_TOKEN", "")
def call_api(path, **params):
try:
response = requests.get(
BASE_URL + path,
params={"token": TOKEN, **params},
timeout=120, allow_redirects=False,
)
except requests.RequestException:
raise RuntimeError("API network error or timeout") from None
if response.status_code != 200:
raise RuntimeError(f"API HTTP {response.status_code}")
try:
result = response.json()
except ValueError:
raise RuntimeError("API response is not JSON") from None
if not isinstance(result, dict) or result.get("code") != 0:
code = result.get("code") if isinstance(result, dict) else None
raise RuntimeError(f"API failed: code={code}; check the docs")
data = result.get("data")
if not isinstance(data, dict):
raise RuntimeError("Unexpected data shape; inspect the docs")
inner = data.get("base_resp")
if isinstance(inner, dict) and inner.get("status_code") not in (0, "0"):
raise RuntimeError("Platform response was unsuccessful")
return result
def save_json(folder, name, value):
(folder / name).write_text(
json.dumps(value, ensure_ascii=False, indent=2), encoding="utf-8"
)
def require_list(data, key):
value = data.get(key)
if not isinstance(value, list):
raise RuntimeError(f"Expected a list at {key}; inspect saved JSON")
return value
def output_folder(topic):
if not TOKEN or TOKEN == "your_token":
raise RuntimeError("Set JUSTONEAPI_TOKEN before running")
run_id = datetime.now(timezone.utc).strftime("%Y%m%dT%H%M%S%fZ")
folder = Path(topic + "-output") / run_id
folder.mkdir(parents=True, exist_ok=False)
return folder
MAX_PAGES = 2
MAX_CREATORS = 3
SEARCH = "/api/xiaohongshu-pgy/api/solar/cooperator/blogger/v2/v1"
PROFILE = "/api/xiaohongshu-pgy/api/solar/cooperator/user/blogger/userId/v1"
AUDIENCE = "/api/xiaohongshu-pgy/api/solar/kol/data/userId/fans_profile/v1"
def main():
folder = output_folder("pugongying")
ids, seen = [], set()
for page in range(1, MAX_PAGES + 1):
result = call_api(
SEARCH, page=page, sort="FANS",
fansNumberLower=10000, fansNumberUpper=100000,
)
save_json(folder, f"search-{page}.json", result)
rows = require_list(result["data"], "kols")
if not rows:
break
previous_count = len(ids)
for row in rows:
uid = row.get("userId") if isinstance(row, dict) else None
if uid and str(uid) not in seen:
seen.add(str(uid))
ids.append(str(uid))
if len(ids) == previous_count:
break
selected = ids[:MAX_CREATORS]
save_json(folder, "selected-creators.json", selected)
summary = []
for index, uid in enumerate(selected, start=1):
profile = call_api(PROFILE, userId=uid)
save_json(folder, f"creator-{index}-profile.json", profile)
audience = call_api(AUDIENCE, userId=uid)
save_json(folder, f"creator-{index}-audience.json", audience)
data = profile["data"]
summary.append({
"userId": uid, "name": data.get("name"),
"fansCount": data.get("fansCount"),
"picturePrice": data.get("picturePrice"),
"videoPrice": data.get("videoPrice"),
"showPrice": data.get("showPrice"),
"audienceDate": audience["data"].get("dateKey"),
})
save_json(folder, "shortlist.json", summary)
print(f"Saved {len(selected)} creator samples to {folder}")
if __name__ == "__main__":
try:
main()
except RuntimeError as error:
raise SystemExit(str(error)) from None如何使用输出结果
每次运行会创建独立的 pugongying-output 时间目录。selected-creators.json 保存选中的 ID,shortlist.json 汇总名称、粉丝数、原始报价及画像日期,各个 creator-*-profile.json 和 creator-*-audience.json 保留完整响应。
先审核候选名单,再按需要扩大详情采集量,有助于控制调用次数。若要转成 CSV,应把未知报价保留为空,并单独标注数据缺失;不要让表格软件把未知值统计成零成本。
常见问题
已经有达人 ID,还要搜索吗?
不需要。确认是对应蒲公英达人的 userId 后,可以直接调用资料和粉丝分布接口。昵称可能重复或发生变化,不适合作为关联主键。
为什么有些报价或画像字段没有值?
字段可用性取决于当次响应。先区分接口失败、完整对象中某字段为空、以及结果列表为空,再决定是否需要重试或人工核对。脚本遇到业务失败会停止,并保留已经保存的成功响应,不会把失败结果包装成有效候选数据。
可以用同一套程序持续更新吗?
可以在这套流程上增加任务调度与增量存储。建议按 userId 和采集时间保留快照,单独记录每次筛选条件,并给分页、并发和重试设置上限。重试方式可参考接口失败后的处理策略。
从达人搜索文档测试一页数据,再按你的筛选条件生成第一份候选名单。
继续使用 Just One API
登录 Dashboard 获取 Token,查看完整 API 文档,或打开 MCP GitHub 项目了解最新配置。