蒲公英笔记博主广场(找博主/选号)/PGY note blogger square
Changed on[中文]
用途:
- 复刻蒲公英网页「找博主 → 笔记博主广场」的搜索与筛选,约 60 个筛选条件按 7 组传入
- 每条结果内嵌约 140 个字段(报价、阅读/互动中位数、直播场次等),通常不必再逐个调博主详情类接口
1. 搜索与排序
| 参数 | 说明 |
|---|---|
| keyword | 搜索词;空=只筛选不搜索 |
| search_type | 1=按笔记关键词找博主(默认)0=按昵称搜 |
| column | 排序字段,共 34 个:comprehensiverank=智能排序(默认) fansCount=粉丝数 price=全部报价 clickNum=阅读中位数-日常 mEngagementNum=互动中位数-日常 accumCommonImpMedinNum30d=曝光中位数-日常 accumPicCommonImpMedinNum30d=图文曝光中位数-日常 accumVideoCommonImpMedinNum30d=视频曝光中位数-日常 pictureClickMidNum=图文阅读中位数-日常 videoClickMidNum=视频阅读中位数-日常 pictureInterMidNum=图文互动中位数-日常 videoInterMidNum=视频互动中位数-日常 thousandLikePercent30=千赞笔记比例 pictureThousandLikePercent30=图文千赞比例 videoThousandLikePercent30=视频千赞比例 hundredLikePercent30=百赞笔记比例 pictureHundredLikePercent30=图文百赞比例 videoHundredLikePercent30=视频百赞比例 videoFinishRate=视频完播率 accumCoopImpMedinNum30d=曝光中位数-合作 readMidCoop30=阅读中位数-合作 interMidCoop30=互动中位数-合作 mCpuvNum30d=外溢进店中位数-合作 picturePrice=图文报价 videoPrice=视频报价 pictureReadCost=图文预估阅读单价 videoReadCost=视频预估阅读单价 inviteReply48hNumRatio=邀约48h回复率 fans30GrowthRate=粉丝量变化幅度 fansActiveIn28dLv=活跃粉丝占比 fansEngageNum30dLv=互动粉丝占比 kliveCnt30d=近30天直播场次 avgLiveViewerNum=场均观播人数 avgAgmv90d=场均销售额 |
| sort | desc 降序(默认)/ asc 升序 |
| brand_user_id | 品牌方/广告主用户ID,可不填。带上后按该品牌做个性化推荐与已合作标记 |
| similar_user_id | 找相似博主:填一个博主的 userId,返回与他相似的博主,并且可以叠加下面所有筛选 |
| similar_word | 配合 similar_user_id 的博主昵称,仅用于回显、不影响结果 |
similar_user_id 与 /get_blogger_similar 是两条不同链路:前者走本接口、能叠加筛选; 后者只按相似度返回、不支持筛选、每页最多 4 条。想「找相似 + 再按粉丝量/报价筛」用前者。
2. 筛选分组
筛选按维度分成 7 组,每组是一个对象:
| 分组 | 覆盖的筛选 |
|---|---|
| goal | 营销目标(曝光 / 种草 / 转化 × 指标 × 成本或规模) |
| blogger | 博主类目、人设、擅长内容、内容题材、二十大人群、行业特色画像、预估消费行为、笔记类目、性别、地域、签约情况 |
| fans | 粉丝量、粉丝年龄、粉丝性别、粉丝地域、婚恋状态、消费水平、母婴阶段、手机价格、手机品牌 |
| note | 日常笔记的曝光/阅读/互动中位数、千赞笔记比例、笔记类型 |
| coop | 合作报价、合作订单数、合作信用度、近期合作行业与品牌、传播规模、预估 CPM / 阅读单价 / 互动单价、外溢进店单价 |
| live | 近 30 天直播场次、场均观播人数、场均销售额 |
| flags | 明星、优质博主、新锐博主、笔记+直播均可合作、意向行业匹配、行业推荐博主、热门活动、剔除低活/掉粉/已合作/已邀约 |
数值区间统一写成 {"min": 10000, "max": 50000}。两端都可省略:省略 min 视为 0, 省略 max 视为不限;但两端全空会 422。
3. 各筛选填什么值
筛选值分三类:照表填的固定枚举、要先查字典的、直接填名称的。 填错不会报错,只会安静返回 0 条 —— 所以拿不到结果时先回来核对这一节。
3.1 固定枚举(照表填,填表外的值直接 422)
左列是请求 JSON 里的路径,例如 fans.age 就是 {"fans": {"age": 3}}。
| 参数路径 | 对应筛选 | 全部取值 |
|---|---|---|
| search_type | 搜笔记 / 搜昵称 | 1=搜笔记(默认)0=搜昵称 |
| sort | 排序方向 | desc=降序(默认)asc=升序 |
| blogger.gender | 性别 | 男 女 |
| blogger.signed | 签约情况 | -1=不限 0=个人博主 1=机构博主 |
| fans.age | 粉丝年龄 | 0=不限 1=<18 2=18 |
| fans.gender | 粉丝性别 | 0=不限 1=男性占比高 2=女性占比高 |
| fans.marital_status | 婚恋状态 | -1=不限 0=未婚 1=已婚 |
| fans.consumption_level | 消费水平 | -1=不限 0=低消费 1=中消费 2=高消费 |
| fans.child_age(数组) | 母婴阶段 | 0=备孕 2=0-6月 3=7-12月 4=1-3岁 5=4-6岁 6=7-12岁 7=孕早期 8=孕晚期 |
| fans.device_price(数组) | 手机价格 | 0-999 1000-1999 2000-2999 3000-3999 4000-4999 5000-5999 6000-6999 7000-7999 8000+ |
| fans.device_brand(数组) | 手机品牌 | 苹果 华为 OPPO VIVO 荣耀 小米 一加 魅族 中兴 联想 |
| note.note_type | 笔记类型 | 0=不限 1=图文笔记为主 2=视频笔记为主 |
| coop.industry | 近期合作行业 | 不限 美妆个护 食品饮料 母婴 3c及电器 日用百货 服装配饰 互联网 生活服务 家居建材 汽车 |
| column | 排序字段 | 34 个,见上面第 1 节的排序字段表 |
| goal.market_target | 营销目标 | 见该字段在 Swagger 中的说明(曝光/种草/转化 × 指标 × 成本或规模) |
3.2 需要先查字典的筛选
下列筛选的可选项由平台维护、会随运营调整。先调 /get_blogger_filter_options 拿字典,再按对应层级填。字典基本不变,建议缓存后复用,不必每次筛选前都调。
这些参数的写法不统一,下表是唯一可靠的对照。 大多数是「裸名、任意层级、可混填」, 但有三个例外(audience20 要复合串、note_scene / consumer_behavior 要全路径、 industry_crowd 要数字 ID),照着别的参数的写法填会失败。
| 参数路径 | 对应筛选 | 字典键 | 填什么 | 能填哪一层 |
|---|---|---|---|---|
| blogger.content_tag | 博主类目 | contentTags | 裸名 | 一级 / 二级,可混填 |
| blogger.personal_tags | 博主人设 | personalTagsV2 | 裸 tagName | 一级 / 二级 / 叶子,可混填 |
| blogger.feature_tags | 擅长内容 | featureTags | 裸名 | 一级 / 二级,可混填 |
| blogger.location | 地域(博主所在地) | areas | 裸地名 | 省 / 市 / 区县,可混填 |
| fans.location | 粉丝地域 | fansAreas | 裸地名 | 省 / 市(没有区县),可混填 |
| blogger.content_theme | 内容题材 | contentTheme | 裸 label | 只有一级,子项无效 |
| blogger.audience20 | 二十大人群 | audience20 | 一级裸名,或 "一级 一级-二级" | 二级必须用复合串 |
| blogger.note_scene | 笔记类目 | contentScenes | 含根节点的空格全路径 | 任意深度 |
| blogger.consumer_behavior | 预估消费行为 | consumerBehavior | 含根节点的空格全路径 | 任意深度 |
| blogger.industry_crowd | 行业特色画像 | automotiveIndustryTag | 最深层叶子的 value(数字 ID) | 只有叶子 |
| flags.industry_first / industry_second | 行业(不是博主类目) | industryTags | 裸名,单值不是数组 | 一级 / 二级各一个 |
| flags.activity_codes | 热门活动 | activities | 每项的 code | — |
数组型参数一律是「或」,多个值取并集去重;上限 30 项、单项 64 字符。
填错了会怎样:两种失败,都不报错
| 失败形态 | 表现 | 哪些参数 |
|---|---|---|
| 过度过滤 | total=0,看起来像「真的没有博主」 | 除 consumer_behavior 外的全部 |
| 静默不过滤 | 返回未经筛选的结果,你以为筛了其实没筛 | consumer_behavior |
实测(粉丝 100 万~120 万,无其它筛选时 total=455):
- content_tag=["护肤品"](多一个字)→ total=0
- fans.location=["浙江省"](多一个「省」)→ total=0
- audience20=["挑战极限者"](照字典 label 裸填)→ total=0
- note_scene=["选车攻略"](只填末段,没填全路径)→ total=0
- industry_crowd=["身心疗愈兴趣人群"](填了 label 不是数字 ID)→ total=0
- consumer_behavior=["保时捷911"](裸叶子名)→ total=455,等于没筛 ;["zzz不存在zzz"] 同样 455。只有全路径写法才真的生效 (["内容行为预估 汽车"] → 54)。
看到 total=0 时先怀疑取值写法,再怀疑「真的没有符合条件的博主」; 看到结果多得可疑时,检查是不是 consumer_behavior 被静默忽略了。 所有取值都应从 /get_blogger_filter_options 里原样复制,不要手写。
博主类目(blogger.content_tag)怎么多选
网页上勾了好几个类目、有的勾「全部」有的只勾几个子项时,就按下面这样填。
contentTags 是两层树:taxonomy1Tag 是一级(美妆、护肤、个人护理…共 28 个), taxonomy2Tags[] 是它的子项。一级名和二级名混在同一个扁平数组里就行, 不用分开传、也没有嵌套结构。二级名全局唯一、也不与一级名重名,所以不会有歧义。
举个网页上的实际场景:美妆勾了「全部」,护肤只勾了 2 个子项,个人护理也勾了 2 个:
{"blogger": {"content_tag": ["美妆", "面部保养", "面部清洁", "头发产品", "身体护理"]}}
其中 美妆 是一级名(= 该类目全部),后面四个是二级名 (面部保养/面部清洁 属于护肤,头发产品/身体护理 属于个人护理)。
实测规则(固定同一组粉丝量条件、只改类目,对比返回的 total):
| 传什么 | total | 说明 |
|---|---|---|
| ["面部保养"] | 200 | — |
| ["面部清洁"] | 2 | — |
| ["面部保养","面部清洁"] | 201 | 多个之间是「或」,并集去重(有 1 个博主两个都占) |
| ["护肤"] | 379 | 一级名 = 该类目全部 |
| 护肤的全部 4 个二级 | 328 | 比一级名少 51 个 |
| ["护肤","面部保养"] | 379 | 父子同填不报错,但子项本就被父项包含,等于只填父 |
| ["护肤品"](错别字) | 0 | 静默返回 0 条、不报错 |
两条要特别注意:
- 勾「全部」就填一级名,别自己展开成它的全部二级名。 上表里护肤展开后少了 51 个博主 —— 有些博主只挂了一级类目、没有二级标签,展开就把他们漏掉了。
- 名字填错不会报错,只会返回 0 条。 务必从 /get_blogger_filter_options 的 contentTags 里原样复制,别手写。看到 total=0 时先怀疑名字,再怀疑「真的没有博主」。
数组最多 30 项,单个标签名最长 64 字符。
地域(blogger.location / fans.location)怎么多选
和类目一样是扁平的:直接填地名,省和市可以混在一起,多个之间是「或」。 网页上浙江勾了「全部」,江苏只勾了 2 个市,广东也勾了 2 个:
{"fans": {"location": ["浙江", "南京", "苏州", "广州", "深圳"]}}
要选整个省就填省名,不用展开成它下面所有的市。博主地域多一层区县,写法一样:
{"blogger": {"location": ["上海", "杭州", "上城区"]}}
上游对这两个字段的要求其实相反(博主地域吃裸地名、粉丝地域吃完整路径 "中国 浙江 杭州"),上游服务会各自转好,你填裸名就行。fans.location 侧 实际会转成:浙江→中国 浙江(不会展开成 11 个市)、杭州→中国 浙江 杭州、 吉林→中国 吉林 和 中国 吉林 吉林(省市同名,两条都发,「或」)。 字典里没有的名字(如 浙江省)原样透传 → total=0。
注意 fans.location 这棵树只到市,没有区县(blogger.location 才有)。
二十大人群(blogger.audience20)怎么多选
这个和上面两个不一样,不是扁平裸名。 二级必须写成 "一级 一级-二级" —— 一级名要出现两次,中间一个空格,后半段用连字符。
网页上自在户外勾了「全部」,自由畅行只勾了 2 个子项,运动焕活也勾了 2 个 (实测 total=169):
{"blogger": {"audience20": [
"自在户外",
"自由畅行 自由畅行-都市漫游家", "自由畅行 自由畅行-静奢新贵",
"运动焕活 运动焕活-轻松健体派", "运动焕活 运动焕活-线条雕塑家"
]}}
注意对比:勾「全部」的那个只写一级裸名,勾了具体子项的每一个都要写成复合串。
实测(基线 455):["自在户外"]=135、["自在户外 自在户外-挑战极限者"]=9、 ["挑战极限者"]=0(照字典 label 裸填,静默返回 0)、两个复合值=18(「或」)、 ["自由畅行","自在户外 自在户外-挑战极限者"]=176(单独 自由畅行=175,可混填)。
博主人设 / 擅长内容 —— 任意层级都能填
personalTagsV2 是三层树,featureTags 是两层,任意一层都能填、可以混填。 想要整组就填那一组的名字,不用把叶子一个个列出来。
{"blogger": {"personal_tags": ["职业身份", "妈妈", "留学背景"],
"feature_tags": ["风格", "vlog"]}}
实测:personal_tags 一级 职业身份=91、二级 互联网=8、叶子 妈妈=31, ["职业身份","妈妈"]=114(并集去重);feature_tags 一级 形式=183、风格=37, 二级 vlog=136、韩系=19,["风格","vlog"]=150。
内容题材(blogger.content_theme)—— 只能填一级
例外:只有一级 label 有效,填子项一律 0 条。实测 ["通用"]=366, 其子项 ["口播"]=0。想按子项筛只能退而求其次用 feature_tags。
笔记类目 / 预估消费行为 —— 必须填「含根节点的空格全路径」
这两个不能填裸名,要把从根节点到目标节点每一层用空格连起来,可以停在任意深度:
{"blogger": {
"note_scene": ["汽车 理性决策", "汽车 理性决策 选车攻略 政策"],
"consumer_behavior": ["内容行为预估 汽车"]
}}
实测 note_scene:["汽车"]=75、["汽车 理性决策"]=23、四级=1, 而只填末段 ["选车攻略"]=0。
⚠️ consumer_behavior 填错的后果和别的参数不一样:不是返回 0 条,而是 整个筛选被静默忽略。实测 ["保时捷911"](裸叶子名)和 ["zzz不存在zzz"] 都返回 455 —— 和完全不加这个筛选一模一样;只有全路径写法才生效 (["内容行为预估 汽车"]=54)。用它时务必用加/不加两次请求的 total 对比确认。 另外这个字典按账号灰度,有些账号取到 null,那就用不了。
行业特色画像(blogger.industry_crowd)—— 只能填数字 ID
四层树,但只有最深层叶子的 value 有效,而且是数字 ID,不是 label。 实测 ["17121263"]=110,填对应 label ["身心疗愈兴趣人群"]=0。
行业(flags.industry_first / industry_second)—— 单值,不能多选
这两个是字符串不是数组,各只能填一个,且要配套使用(二级必须属于一级):
{"flags": {"industry_first": "美妆个护", "industry_second": "护肤"}}
注意这是「行业」,和「博主类目」(blogger.content_tag)是两套完全不同的分类。
3.3 直接填名称的筛选
| 参数路径 | 对应筛选 | 怎么填 |
|---|---|---|
| coop.brand_ids | 近期合作品牌 | 品牌方 userId 列表(平台暂无品牌搜索接口,userId 需自行提供) |
想按粉丝人群圈博主,用 blogger.audience20(二十大人群)而不是 coop.brand_ids。
3.4 区间型字段(值写成 {"min": x, "max": y})
| 参数路径 | 对应网页筛选 |
|---|---|
| fans.count | 粉丝量 |
| note.imp_median / note.read_median / note.inter_median | 日常笔记的曝光 / 阅读 / 互动中位数 |
| note.thousand_like_percent | 千赞笔记比例(单位 %) |
| coop.pic_price / coop.video_price | 合作报价(图文 / 视频一口价,元) |
| coop.order_count | 合作订单数 |
| coop.reply_48h_ratio | 合作信用度 → 48h 邀约回复率(%) |
| coop.imp_median / coop.read_median / coop.inter_median | 传播规模(合作笔记的中位数) |
| coop.cpuv / coop.estimate_cpuv | CPUV / 外溢进店单价 |
| coop.pic_cpm / coop.video_cpm | 预估 CPM(图文 / 视频) |
| coop.pic_read_price / coop.video_read_price | 预估阅读单价(图文 / 视频) |
| coop.pic_engage_cost / coop.video_engage_cost | 预估互动单价(图文 / 视频) |
| live.live_count / live.avg_viewer / live.avg_gmv | 近 30 天直播场次 / 场均观播 / 场均销售额 |
3.5 开关型字段(值写 true)
| 参数路径 | 对应网页筛选 |
|---|---|
| flags.is_star / flags.high_quality / flags.new_high_quality | 明星 / 优质博主 / 新锐博主 |
| flags.note_and_live | 笔记 + 直播均可合作 |
| flags.filter_intention | 意向行业匹配 |
| flags.exclude_low_active / flags.exclude_fans_down | 剔除低活 / 掉粉博主 |
| flags.exclude_cooperated / flags.exclude_invited | 剔除已合作 / 已邀约博主 |
| coop.exclude_brands | 配合 coop.brand_ids:true = 排除与这些品牌合作过的博主 |
此外 flags.industry_first / flags.industry_second 是行业推荐博主的一级/二级行业名, flags.activity_codes 是热门活动 code(取自 /get_blogger_filter_options 的 activities)。 枚举型字段(性别、签约情况、粉丝年龄等)的完整取值见各字段在 Swagger 中的说明。
4. 更多示例
本页最下方的 [示例/Example] 区里有 15 条可直接照抄的请求体,覆盖关键词搜索、画像选号、预算/性价比、直播带货、找相似博主、地域投放等场景,外加一节常见错误写法(那几种不会报错、只会安静返回 0 条)。
5. 翻页
| 参数 | 取值 | 说明 |
|---|---|---|
| page_num | 1-250 | 上游只放出前 5000 条 = 250 页,第 251 页起返回空数组 |
| page_size | 1-20 | 蒲公英网页固定 20。建议保持 20:上游会对当页结果做二次过滤(下架、不可合作等),取太小可能整页被过滤成 0 条 |
翻页只改 page_num,其余筛选必须原样保持不变,否则两页口径不一致会重复或遗漏。 total 不是命中总数,是可翻上限,恒为 5000。想缩小结果集请加筛选,而不是指望翻到底。
6. 返回
- kols[]: 命中的博主,每条约 140 个字段
- 身份: userId / name / redId / headPhoto / location / gender
- 标签: contentTags / featureTags / personalTags / tradeType
- 数据: fansNum / clickMidNum 阅读中位数 / interMidNum 互动中位数 / fans30GrowthRate 粉丝增速 / kliveCnt30d 直播场次
- 商业: picturePrice / videoPrice / lowerPrice / estimatePictureCpm / cooperateState
- total: 可翻上限(恒 5000)
- trackId / highlightWords
7. 注意:
- 字段名写错会直接 422,不会被静默忽略
- 树形筛选的可选值请用 /get_blogger_filter_options 实时拉取,不要写死
响应结构(取数要剥两层):
- resp["data"] 是蒲公英原样信封(含 code/msg/success),业务数据还在它里面一层
- 正确取法:data = resp["data"]["data"];下面「返回」列的字段都在这一层下
计费:
- HTTP 200 → 计费。包含「查无结果」(data 为 null,如 ID 不存在或筛选无命中)—— 请求已送达蒲公英,同样扣费,不要因为拿不到数据就重试
- HTTP 400 → 不计费(参数格式非法,或上游资源不足/异常)
[English]
Purpose:
- Full replica of PGY "Find Bloggers → Note Blogger Square"; ~60 filters grouped into 7 objects
- Each result embeds ~140 fields (quotes, read/engagement medians, live sessions, ...)
1. Search & Sort
| Param | Description |
|---|---|
| keyword | Search term; empty = filter only |
| search_type | 1=find bloggers by note keyword (default), 0=search by nickname |
| column | Sort field, 34 options — see the Chinese table above for the full list with labels |
| similar_user_id | Find similar bloggers: pass a blogger's userId; results can be combined with every filter below |
| similar_word | Nickname echo for similar_user_id; does not affect results |
| sort | desc (default) / asc |
| brand_user_id | Brand/advertiser user ID, optional; enables brand-specific recommendation and "already cooperated" marks |
2. Filter Groups
| Group | Covers |
|---|---|
| goal | Marketing goal (exposure / seeding / conversion × metric × cost or scale) |
| blogger | Category, persona, expertise, content theme, top-20 crowds, industry-specific portrait, estimated consumption, note category, gender, location, agency status |
| fans | Fans count, age, gender, location, marital status, consumption level, parenting stage, phone price, phone brand |
| note | Organic note impression / read / engagement medians, 1000-like ratio, note type |
| coop | Quotes, order count, credit score, recent industries & brands, reach scale, estimated CPM / read cost / engagement cost, store-visit cost |
| live | Live sessions in last 30d, average viewers, average GMV |
| flags | Celebrity, high-quality, rising bloggers, note+live capable, intention match, industry recommendation, campaigns, exclude inactive / fans-declining / already-cooperated / already-invited |
Numeric ranges are written as {"min": 10000, "max": 50000}. Either bound may be omitted (omitting min means 0, omitting max means unlimited), but omitting both returns 422.
3. What Values Go In Each Filter
Filter values come in three kinds: fixed enums (copy from the table), dictionary-backed (fetch first), and plain names. A wrong value does not raise — it just silently returns 0 results, so check this section first when a query comes back empty.
3.1 Fixed enums (values outside the table return 422)
| Path | Web filter | Allowed values |
|---|---|---|
| search_type | Search notes / nickname | 1=notes (default) 0=nickname |
| sort | Sort direction | desc (default) / asc |
| blogger.gender | Gender | 男 女 |
| blogger.signed | Agency status | -1=any 0=individual 1=agency |
| fans.age | Fans age | 0=any 1=<18 2=18 |
| fans.gender | Fans gender | 0=any 1=male-skewed 2=female-skewed |
| fans.marital_status | Marital status | -1=any 0=single 1=married |
| fans.consumption_level | Consumption level | -1=any 0=low 1=mid 2=high |
| fans.child_age (array) | Parenting stage | 0 2 3 4 5 6 7 8 |
| fans.device_price (array) | Phone price | 0-999 … 8000+ |
| fans.device_brand (array) | Phone brand | 苹果 华为 OPPO VIVO 荣耀 小米 一加 魅族 中兴 联想 |
| note.note_type | Note type | 0=any 1=image-text 2=video |
| coop.industry | Recent industry | 不限 美妆个护 食品饮料 母婴 3c及电器 日用百货 服装配饰 互联网 生活服务 家居建材 汽车 |
| column | Sort field | 34 options — see the sort table in section 1 |
3.2 Dictionary-backed filters
Call /get_blogger_filter_options first, then fill values from the matching level. The dictionary rarely changes — cache it rather than calling it before every search.
These parameters do NOT share one convention — this table is the only reliable reference. Most take plain names at any level and can be mixed, but three are exceptions (audience20 needs a compound string, note_scene / consumer_behavior need a full path, industry_crowd needs a numeric ID). Copying the convention from another parameter will fail.
| Path | Web filter | Dict key | What to pass | Which level |
|---|---|---|---|---|
| blogger.content_tag | Blogger category | contentTags | plain name | level 1 / 2, mixable |
| blogger.personal_tags | Persona | personalTagsV2 | plain tagName | level 1 / 2 / leaf, mixable |
| blogger.feature_tags | Expertise | featureTags | plain name | level 1 / 2, mixable |
| blogger.location | Blogger location | areas | plain place name | province / city / district, mixable |
| fans.location | Fans location | fansAreas | plain place name | province / city (no district), mixable |
| blogger.content_theme | Content theme | contentTheme | plain label | level 1 only, children invalid |
| blogger.audience20 | Top-20 crowds | audience20 | level-1 name, or "L1 L1-L2" | level 2 needs the compound form |
| blogger.note_scene | Note category | contentScenes | space-joined full path incl. root | any depth |
| blogger.consumer_behavior | Estimated consumption | consumerBehavior | space-joined full path incl. root | any depth |
| blogger.industry_crowd | Industry portrait | automotiveIndustryTag | deepest leaf value (numeric ID) | leaves only |
| flags.industry_first / industry_second | Industry (not blogger category) | industryTags | plain name, single value, not an array | one each |
| flags.activity_codes | Campaigns | activities | each item's code | — |
Array parameters are always OR-ed (union, de-duplicated); max 30 items, 64 characters per item.
Two ways a wrong value fails — neither raises an error
| Failure | What you see | Which parameters |
|---|---|---|
| Over-filtering | total=0, looks like "no such bloggers" | everything except consumer_behavior |
| Silently not filtering | unfiltered results — you think it applied, it didn't | consumer_behavior |
Measured (fans 1.0M–1.2M, total=455 with no other filter):
- content_tag=["护肤品"] (one extra character) → total=0
- fans.location=["浙江省"] (extra 省) → total=0
- audience20=["挑战极限者"] (bare level-2 label) → total=0
- note_scene=["选车攻略"] (last segment only, not the full path) → total=0
- industry_crowd=["身心疗愈兴趣人群"] (label instead of numeric ID) → total=0
- consumer_behavior=["保时捷911"] (bare leaf) → total=455 — no filtering at all; ["zzz不存在zzz"] also returns 455. Only the full-path form works (["内容行为预估 汽车"] → 54).
When you get total=0, suspect the value format before concluding "no such bloggers". When you get suspiciously many results, check whether consumer_behavior was silently ignored. Always copy values verbatim from /get_blogger_filter_options.
How to fill location (the most common mistake): just pass the plain place name — ["上海"], ["杭州"], ["上城区"] all work, OR-ed together. A full path ("中国 浙江 杭州") also works; upstream normalizes it. The only difference: fans.location has no district level — city is the finest.
Selecting multiple blogger categories (blogger.content_tag)
contentTags is a two-level tree: taxonomy1Tag is level 1 (28 of them — 美妆, 护肤, 个人护理 …) and taxonomy2Tags[] are its children. Mix level-1 and level-2 names in the same flat array — there is no nesting and nothing to send separately. Level-2 names are globally unique and never collide with level-1 names, so a flat array is unambiguous.
A real case from the web UI: 美妆 = "all", plus 2 children of 护肤 and 2 of 个人护理:
{"blogger": {"content_tag": ["美妆", "面部保养", "面部清洁", "头发产品", "身体护理"]}}
美妆 is a level-1 name (= the whole category); the other four are level-2 names.
Measured behaviour (same fan-count filter throughout, only the category changed, comparing the returned total):
| Value | total | Note |
|---|---|---|
| ["面部保养"] | 200 | — |
| ["面部清洁"] | 2 | — |
| ["面部保养","面部清洁"] | 201 | Multiple tags are OR-ed, de-duplicated (1 blogger has both) |
| ["护肤"] | 379 | A level-1 name means the whole category |
| all 4 children of 护肤 | 328 | 51 fewer than the level-1 name |
| ["护肤","面部保养"] | 379 | Parent + child is accepted but pointless — the child is already covered |
| ["护肤品"] (typo) | 0 | Silently returns 0 — no error |
Two things to watch out for:
- For "all", pass the level-1 name — do NOT expand it into all its children. Expanding 护肤 above loses 51 bloggers: some carry only the level-1 category and have no level-2 tag, so expanding drops them.
- A misspelled name is not rejected — it just returns 0 results. Copy names verbatim from contentTags in /get_blogger_filter_options. When you see total=0, suspect the spelling before concluding "no such bloggers".
Max 30 items per array; each tag name at most 64 characters.
Locations (blogger.location / fans.location)
Flat, like categories: pass plain place names; provinces and cities can be mixed; multiple values are OR-ed. The web-UI case — 浙江 set to "all", 2 cities picked under 江苏, 2 more under 广东:
{"fans": {"location": ["浙江", "南京", "苏州", "广州", "深圳"]}}
For a whole province just pass the province name — do not expand it into all its cities. Blogger location has one extra level (district), same syntax:
{"blogger": {"location": ["上海", "杭州", "上城区"]}}
Upstream actually wants opposite formats for these two fields (blogger location takes bare names, fans location takes full paths like "中国 浙江 杭州"); the upstream service normalizes each, so plain names are all you need. On the fans.location side: 浙江→中国 浙江 (not expanded into its 11 cities), 杭州→中国 浙江 杭州, 吉林→ both 中国 吉林 and 中国 吉林 吉林 (a province and a city share that name; both are sent, OR-ed). A name absent from the dictionary (e.g. 浙江省) is passed through as-is → total=0.
Note fans.location only goes down to city — no districts (blogger.location has them).
Top-20 crowds (blogger.audience20)
This one is NOT a flat plain name. Level 2 must be written as "L1 L1-L2" — the level-1 name appears twice, separated by a space, joined by a hyphen in the second half.
The web-UI case — 自在户外 set to "all", 2 children under 自由畅行, 2 under 运动焕活 (measured total=169):
{"blogger": {"audience20": [
"自在户外",
"自由畅行 自由畅行-都市漫游家", "自由畅行 自由畅行-静奢新贵",
"运动焕活 运动焕活-轻松健体派", "运动焕活 运动焕活-线条雕塑家"
]}}
Note the contrast: the "all" one is a bare level-1 name; every individually picked child must use the compound form.
Measured (baseline 455): ["自在户外"]=135, ["自在户外 自在户外-挑战极限者"]=9, ["挑战极限者"]=0 (bare level-2 label — silently returns 0), two compound values=18 (OR), ["自由畅行","自在户外 自在户外-挑战极限者"]=176 (vs 175 for 自由畅行 alone — mixing works).
Persona / Expertise — any level works
personalTagsV2 is a three-level tree, featureTags two. Any level works and they can be mixed. For a whole group just pass that group's name — no need to enumerate its leaves.
{"blogger": {"personal_tags": ["职业身份", "妈妈", "留学背景"],
"feature_tags": ["风格", "vlog"]}}
Measured: personal_tags level-1 职业身份=91, level-2 互联网=8, leaf 妈妈=31, ["职业身份","妈妈"]=114 (union). feature_tags level-1 形式=183, 风格=37; level-2 vlog=136, 韩系=19; ["风格","vlog"]=150.
Content theme (blogger.content_theme) — level 1 only
An exception: only the level-1 label works; children always return 0. Measured ["通用"]=366 but its child ["口播"]=0. To filter by a child, use feature_tags instead.
Note category / Estimated consumption — full path required
These two do not take plain names. Join every level from the root with spaces; you may stop at any depth:
{"blogger": {
"note_scene": ["汽车 理性决策", "汽车 理性决策 选车攻略 政策"],
"consumer_behavior": ["内容行为预估 汽车"]
}}
Measured note_scene: ["汽车"]=75, ["汽车 理性决策"]=23, 4-level=1, while the last segment alone ["选车攻略"]=0.
⚠️ consumer_behavior fails differently from every other parameter: instead of returning 0, the whole filter is silently ignored. Measured ["保时捷911"] (bare leaf) and ["zzz不存在zzz"] both return 455 — identical to not passing the filter at all. Only the full-path form works (["内容行为预估 汽车"]=54). When using it, compare total with and without the filter to confirm it applied. This dictionary is also rolled out per account — some accounts get null, in which case the filter is unavailable.
Industry portrait (blogger.industry_crowd) — numeric IDs only
A four-level tree, but only the deepest leaf's value works, and it is a numeric ID, not a label. Measured ["17121263"]=110; the matching label ["身心疗愈兴趣人群"]=0.
Industry (flags.industry_first / industry_second) — single value
These are strings, not arrays — one value each, used together (the level-2 value must belong to the level-1 one):
{"flags": {"industry_first": "美妆个护", "industry_second": "护肤"}}
This is industry, a completely different taxonomy from blogger category (blogger.content_tag).
3.3 Plain-name filters
| Path | Web filter | How to fill |
|---|---|---|
| coop.brand_ids | Recent brands | Brand userId list (no brand search endpoint — supply userIds yourself) |
3.4 Range Fields (value = {"min": x, "max": y})
| Path | Web filter |
|---|---|
| fans.count | Fans count |
| note.imp_median / note.read_median / note.inter_median | Organic note impression / read / engagement median |
| note.thousand_like_percent | 1000-like note ratio (%) |
| coop.pic_price / coop.video_price | Sponsored quote (image-text / video, CNY) |
| coop.order_count | Sponsored order count |
| coop.reply_48h_ratio | 48h invitation reply rate (%) |
| coop.imp_median / coop.read_median / coop.inter_median | Sponsored note medians |
| coop.cpuv / coop.estimate_cpuv | CPUV / store-visit cost |
| coop.pic_cpm / coop.video_cpm | Estimated CPM (image-text / video) |
| coop.pic_read_price / coop.video_read_price | Estimated cost per read |
| coop.pic_engage_cost / coop.video_engage_cost | Estimated cost per engagement |
| live.live_count / live.avg_viewer / live.avg_gmv | Live sessions / avg viewers / avg GMV |
3.5 Boolean Flags (value = true)
| Path | Web filter |
|---|---|
| flags.is_star / flags.high_quality / flags.new_high_quality | Celebrity / high-quality / rising blogger |
| flags.note_and_live | Accepts both note and live cooperation |
| flags.filter_intention | Industry intention match |
| flags.exclude_low_active / flags.exclude_fans_down | Exclude inactive / fans-declining bloggers |
| flags.exclude_cooperated / flags.exclude_invited | Exclude already-cooperated / already-invited |
| coop.exclude_brands | With coop.brand_ids: true = exclude bloggers who worked with those brands |
flags.industry_first / flags.industry_second are industry names for industry-recommended bloggers; flags.activity_codes are campaign codes from /get_blogger_filter_options.
4. More Examples
The [示例/Example] block at the bottom of this page has 15 ready-to-copy request bodies covering keyword search, audience targeting, budget/ROI, live commerce, similar-blogger expansion and geo targeting — plus a common mistakes section (those silently return 0 results instead of erroring).
5. Paging
| Param | Range | Note |
|---|---|---|
| page_num | 1-250 | Upstream exposes only the first 5000 items = 250 pages; page 251+ returns an empty array |
| page_size | 1-20 | Fixed at 20 on the web page. Keep it at 20: upstream post-filters each page, so a small size may leave 0 rows |
Change page_num only and keep every other filter identical, otherwise pages overlap or skip. total is not the match count, it is the paging cap and is always 5000.
6. Return
- kols[]: matched bloggers (~140 fields each)
- Identity: userId / name / redId / headPhoto / location / gender
- Tags: contentTags / featureTags / personalTags / tradeType
- Metrics: fansNum / clickMidNum (read median) / interMidNum (engagement median) / fans30GrowthRate (fan growth) / kliveCnt30d (live sessions)
- Commercial: picturePrice / videoPrice / lowerPrice / estimatePictureCpm / cooperateState
- total: paging cap (always 5000 — not the real match count, see Paging above)
- trackId / highlightWords
7. Notes:
- Misspelled field names return 422 instead of being silently ignored
- Fetch tree-style option values from /get_blogger_filter_options instead of hardcoding them
Response shape (two layers):
- resp["data"] is PGY's raw envelope (with code/msg/success); the payload is one level deeper
- Correct access: data = resp["data"]["data"] — every field listed under "Return" lives here
Billing:
- HTTP 200 → charged, including "no result" (data is null, e.g. ID not found or filters matched nothing): the request did reach PGY, so retrying on empty data just burns quota
- HTTP 400 → not charged (malformed params, or upstream unavailable/error)
[示例/Example]
// ① 关键词找博主:搜「咖啡」相关笔记的博主,按粉丝数降序;带品牌方 ID 做个性化推荐并剔除已合作过的
{"page_num": 1, "page_size": 20, "keyword": "咖啡", "search_type": 1,
"column": "fansCount", "sort": "desc",
"brand_user_id": "5dcfa5370000000001006030",
"flags": {"exclude_cooperated": true}}
// ② 按昵称找号:search_type=0 时 keyword 匹配的是博主昵称而不是笔记内容
{"page_num": 1, "page_size": 20, "keyword": "小鹿", "search_type": 0}
// ③ 最基础的类目 + 粉丝量筛选:粉丝 1 万-5 万的美妆博主,按互动中位数降序
{"page_num": 1, "page_size": 20, "column": "mEngagementNum",
"fans": {"count": {"min": 10000, "max": 50000}},
"blogger": {"content_tag": ["美妆"]}}
// ④ 按画像选号:1 万-5 万粉、粉丝以 25-34 岁女性为主的美妆「妈妈」博主
{"page_num": 1, "page_size": 20,
"blogger": {"content_tag": ["美妆"], "personal_tags": ["妈妈"]},
"fans": {"count": {"min": 10000, "max": 50000}, "gender": 2, "age": 3}}
// ⑤ 按预算与响应速度选号:图文报价 1 万-5 万、48h 邀约回复率 ≥80%
{"page_num": 1, "page_size": 20,
"coop": {"pic_price": {"min": 10000, "max": 50000},
"reply_48h_ratio": {"min": 80}}}
// ⑥ 按性价比选号:图文报价 ≤5000、阅读中位数 ≥3000 的视频博主,只看优质号并剔除低活
{"page_num": 1, "page_size": 20,
"note": {"read_median": {"min": 3000}, "note_type": 2},
"coop": {"pic_price": {"max": 5000}},
"flags": {"high_quality": true, "exclude_low_active": true}}
// ⑦ 找会直播带货的博主:近 30 天开播 1-5 场、场均销售额 ≥1 万,且笔记+直播均可合作
{"page_num": 1, "page_size": 20,
"live": {"live_count": {"min": 1, "max": 5}, "avg_gmv": {"min": 10000}},
"flags": {"note_and_live": true}}
// ⑧ 多维组合:7 个筛选组同时生效(字段名写错会直接 422,不会被静默忽略)
{"page_num": 1, "page_size": 20, "column": "comprehensiverank", "sort": "desc",
"goal": {"market_target": "mAccumImpNum"},
"blogger": {"content_tag": ["美妆"], "gender": "女", "signed": 0},
"fans": {"count": {"min": 10000}, "age": 3, "device_brand": ["苹果"]},
"note": {"inter_median": {"min": 500}, "thousand_like_percent": {"min": 20}},
"coop": {"industry": "美妆个护", "video_price": {"max": 8000}},
"live": {"avg_viewer": {"min": 5000}},
"flags": {"exclude_cooperated": true}}
// ⑨ 找相似博主:给一个满意的标杆博主,扩一批相似的,**并叠加自己的筛选**
// (/get_blogger_similar 只按相似度返回、不支持筛选,需要叠加筛选就用这里)
{"page_num": 1, "page_size": 20,
"similar_user_id": "5a8cf39111be10466d285d6b",
"fans": {"count": {"min": 50000}},
"coop": {"pic_price": {"max": 20000}}}
// ⑩ 预算优先:按「图文预估阅读单价」从低到高排,先看最便宜的
{"page_num": 1, "page_size": 20,
"column": "pictureReadCost", "sort": "asc",
"coop": {"pic_price": {"min": 1000, "max": 10000}}}
// ⑪ 涨粉快的新秀:按近 30 天粉丝增长率降序,并剔除掉粉的
{"page_num": 1, "page_size": 20,
"column": "fans30GrowthRate", "sort": "desc",
"fans": {"count": {"min": 5000, "max": 100000}},
"flags": {"exclude_fans_down": true}}
// ⑫ 爆款率优先:按百赞笔记占比降序(看重内容稳定性而非粉丝量时用)
{"page_num": 1, "page_size": 20,
"column": "hundredLikePercent30", "sort": "desc",
"note": {"thousand_like_percent": {"min": 10}}}
// ⑬ 地域投放:找上海本地的探店博主
// blogger.location 直接填地名即可,不要填「上海市-上海市-黄浦区」这种全路径
{"page_num": 1, "page_size": 20,
"blogger": {"location": ["上海"], "content_tag": ["美食"]}}
// ⑭ 按粉丝所在地投放(和 ⑬ 是两个不同维度:⑬ 是博主在哪,⑭ 是粉丝在哪)
{"page_num": 1, "page_size": 20,
"fans": {"location": ["广东"], "count": {"min": 20000}}}
// ⑮ 直播带货 + 90 天口径:场均观播 ≥5000、场均销售额 ≥1 万
// 注意 avg_viewer / avg_gmv 是近 90 天,而 live_count 是近 30 天
{"page_num": 1, "page_size": 20,
"live": {"live_count": {"min": 1}, "avg_viewer": {"min": 5000}, "avg_gmv": {"min": 10000}}}
常见错误写法 / Common mistakes
分两类。第二类才是真正的坑 —— 它们不会报错,只会安静返回 0 条。
A. 会直接 422 的写法(好在会立刻报错)
// ✗ 区间写成了数字 —— 区间型字段必须是对象
{"fans": {"count": 10000}}
// ✓
{"fans": {"count": {"min": 10000}}}
// ✗ 字段名拼错(驼峰)—— 本接口 extra="forbid",写错直接 422,不会被静默忽略
{"blogger": {"contentTag": ["美妆"]}}
// ✓
{"blogger": {"content_tag": ["美妆"]}}
// ✗ 排序列填了未放行的值
{"column": "forecastReadUv"}
// ✓ 见第 1 节的 34 个排序字段
{"column": "avgAgmv90d"}
// ✗ page_size 超上限(1-20)
{"page_size": 100}
// ✓
{"page_size": 20}
// ✗ 百分比量纲错了 —— 千赞比例填 200 或 9500(按万分比/原始条数填)
{"note": {"thousand_like_percent": {"min": 200}}}
// ✓ 想表达「20%」就填 20
{"note": {"thousand_like_percent": {"min": 20}}}
B. 不会报错、但查不到数据的写法(最难排查)
下面这些全都能通过校验,返回 200,结果却是 0 条 —— 因为值本身合法、只是没有匹配项。
// ✗ 地域填了带分隔符的全路径
{"blogger": {"location": ["上海市-上海市-黄浦区"]}}
// ✓ 直接填地名
{"blogger": {"location": ["上海"]}}
// ✗ 百分比填了小数(0.2 是合法的 0.2%,不是 20%)
{"note": {"thousand_like_percent": {"min": 0.2}}}
// ✓ 想表达「20%」
{"note": {"thousand_like_percent": {"min": 20}}}
// ✗ 类目值是自己编的
{"blogger": {"content_tag": ["美妆护肤"]}}
// ✓ 用 /get_blogger_filter_options 的 contentTags 里真实存在的值
{"blogger": {"content_tag": ["美妆"]}}
// ✗ 开关型填 false —— 等于没筛,不是「反向筛」
{"flags": {"exclude_cooperated": false}}
// ✓ 想生效就填 true
{"flags": {"exclude_cooperated": true}}
// ✗ 把「行业」当成「博主类目」用(两个是不同的筛选)
{"flags": {"industry_first": "美妆"}}
// ✓ 博主类目用 blogger.content_tag
{"blogger": {"content_tag": ["美妆"]}}
搜不到结果时的排查顺序:先把筛选一个个去掉,定位是哪个条件卡住的; 需要查字典的筛选(类目 / 场景 / 消费行为 / 地域)优先怀疑值写错了。
Request
- Base URLhttps://api.tikhub.io (the document declares no server; this is the origin it was published from)
- AuthHTTP bearer
Request body
Example request
{
"page_num": 1,
"page_size": 20,
"keyword": "咖啡",
"search_type": 1,
"column": "comprehensiverank",
"sort": "desc",
"brand_user_id": "5dcfa5370000000001006030",
"similar_user_id": "5c668b3e0000000012021605",
"goal": {
"market_target": "mAccumImpNum"
},
"blogger": {
"content_tag": [
"美妆",
"面部保养",
"面部清洁"
],
"personal_tags": [
"妈妈"
],
"feature_tags": [
"vlog"
],
"content_theme": [
"汽车特色"
],
"audience20": [
"自由畅行",
"自在户外 自在户外-挑战极限者"
],
"industry_crowd": [
"15795914"
],
"consumer_behavior": [
"内容行为预估 汽车"
],
"note_scene": [
"汽车 理性决策 选车攻略 政策"
],
"gender": "女",
"location": [
"上海"
]
},
"fans": {
"count": {
"min": 10000,
"max": 50000
},
"age": 3,
"gender": 2,
"device_price": [
"3000-3999"
],
"device_brand": [
"苹果"
],
"location": [
"上海"
]
},
"note": {
"imp_median": {
"min": 10000,
"max": 50000
},
"read_median": {
"min": 10000,
"max": 50000
},
"inter_median": {
"min": 10000,
"max": 50000
},
"thousand_like_percent": {
"min": 20,
"max": 80
},
"note_type": 2
},
"coop": {
"pic_price": {
"min": 10000,
"max": 50000
},
"video_price": {
"min": 10000,
"max": 50000
},
"order_count": {
"min": 10000,
"max": 50000
},
"reply_48h_ratio": {
"min": 20,
"max": 80
},
"industry": "美妆个护",
"imp_median": {
"min": 10000,
"max": 50000
},
"read_median": {
"min": 10000,
"max": 50000
},
"inter_median": {
"min": 10000,
"max": 50000
},
"cpuv": {
"min": 10000,
"max": 50000
},
"pic_cpm": {
"min": 10000,
"max": 50000
},
"video_cpm": {
"min": 10000,
"max": 50000
},
"pic_read_price": {
"min": 10000,
"max": 50000
},
"video_read_price": {
"min": 10000,
"max": 50000
},
"pic_engage_cost": {
"min": 10000,
"max": 50000
},
"video_engage_cost": {
"min": 10000,
"max": 50000
},
"estimate_cpuv": {
"min": 10000,
"max": 50000
}
},
"live": {
"live_count": {
"min": 10000,
"max": 50000
},
"avg_viewer": {
"min": 10000,
"max": 50000
},
"avg_gmv": {
"min": 10000,
"max": 50000
}
},
"flags": {
"industry_first": "美妆个护"
}
}Response
Successful Response
Changes
- breaking
removed from the
request propertyanyOflist - info
added to the
request propertyanyOflist - info
added the optional property
//to the response with the status - info
added the optional property
//to the response with the status
- breaking
- breaking
removed from the
request propertyanyOflist - breaking
removed from the
request propertyanyOflist - info
added to the
request propertyanyOflist - info
added to the
request propertyanyOflist
- breaking