小红书笔记评论 API 接口深度解析(带全套 JSON 示例・技术实战版)
一、接口基础说明
1. 接口基础信息
接口路径:/api/v1/note/comment/list(小红书开放平台标准评论接口)
请求方式:POST鉴权规则:Header 携带Authorization: Bearer access_token(OAuth2.0 令牌鉴权)分页规则:游标 cursor 分页(弃用传统 page 页码),首次请求 cursor 传空字符串,下一页使用上一页返回 cursor 字段;sort支持hot热门排序 /time时间倒序;page_size单页 1~50 条,官方 QPS 限流 5 次 /s。
请求入参(JSON 入参示例)
json
{ "note_id": "649c46ab000000002702ad36", "cursor": "", "page_size": 20, "sort": "hot", "need_sub_comment": true }
表格
| 参数 | 必填 | 说明 |
| note_id | 是 | 笔记唯一 ID(32 位字符串,从笔记链接提取) |
| cursor | 否 | 分页游标,空 = 第一页 |
| page_size | 否 | 单页评论条数,默认 20 |
| sort | 否 | hot = 热门优先,time = 最新优先 |
| need_sub_comment | 否 | true 返回楼中楼子评论 |
二、接口原生返回完整 JSON(真实脱敏样例)
原生 JSON 层级深、嵌套子评论数组、时间为时间戳、用户信息内嵌,无法直接入库 / 数据分析:
json
{ "code": 200, "msg": "success", "request_id": "req_987654321abc", "data": { "note_id": "649c46ab000000002702ad36", "total_comment": 1256, "cursor": "crs_20260603_001", "has_more": true, "comments": [ { "comment_id": "com_1122334455", "content": "油皮亲妈!上脸清爽不闷痘,已经囤两瓶啦🥰", "create_time": 1744289620, "like_count": 326, "reply_count": 18, "is_top": true, "user": { "user_id": "u_589abc789", "nickname": "油痘肌避雷君", "avatar": "https://sns-avatar-qc.xhscdn.com/avatar/abc123.jpg", "is_creator": false }, "sub_comments": [ { "comment_id": "sub_998877", "content": "想问多少钱入手的?", "create_time": 1744290120, "like_count": 12, "reply_user_id": "u_589abc789", "user": { "user_id": "u_321def654", "nickname": "奶茶不加冰", "avatar": "https://sns-avatar-qc.xhscdn.com/avatar/def456.jpg" } } ] }, { "comment_id": "com_5566778899", "content": "@小丸子 敏感肌能用吗?", "create_time": 1744291200, "like_count": 45, "reply_count": 0, "is_top": false, "user": { "user_id": "u_789ghi123", "nickname": "护肤小白日常", "avatar": "https://sns-avatar-qc.xhscdn.com/avatar/ghi789.jpg", "is_creator": false }, "sub_comments": [] } ] } }
顶层字段释义
code:200 = 请求成功;401=token 失效;403 = 权限不足;429 = 接口限流request_id:请求唯一标识,接口异常排查日志用data.total_comment:笔记全量评论总数data.has_more:true = 存在下一页数据,继续游标翻页
三、原生 JSON 痛点
- 时间为Unix 时间戳,业务需要格式化
yyyy-MM-dd HH:mm:ss; - 主评论、子评论分层嵌套,子评论归属关系不直观;
- 用户信息内嵌在 comment 对象内,字段分散不利于分表存储(评论表 + 用户表);
- 置顶标识
is_top零散,批量筛选置顶评论需额外遍历; - @关联用户无结构化字段,原文 content 混 @文本,关键词提取困难。
四、结构化解析后标准 JSON(落地入库模型)
扁平化结构,拆分主评论 / 子评论、格式化时间、规整用户信息,可直接存入 MySQL/ES,用于舆情分析、竞品评论统计:
json
{ "note_id": "649c46ab000000002702ad36", "total_comment": 1256, "next_cursor": "crs_20260603_001", "has_more": true, "main_comments": [ { "comment_id": "com_1122334455", "comment_type": "main", "content": "油皮亲妈!上脸清爽不闷痘,已经囤两瓶啦🥰", "create_time_stamp": 1744289620, "create_time": "2025-06-10 15:53:40", "like_count": 326, "reply_count": 18, "is_top": true, "user_info": { "user_id": "u_589abc789", "nickname": "油痘肌避雷君", "avatar": "https://sns-avatar-qc.xhscdn.com/avatar/abc123.jpg" }, "sub_comments": [ { "comment_id": "sub_998877", "comment_type": "sub", "parent_comment_id": "com_1122334455", "content": "想问多少钱入手的?", "create_time_stamp": 1744290120, "create_time": "2025-06-10 16:02:00", "like_count": 12, "reply_target_uid": "u_589abc789", "user_info": { "user_id": "u_321def654", "nickname": "奶茶不加冰", "avatar": "https://sns-avatar-qc.xhscdn.com/avatar/def456.jpg" } } ] }, { "comment_id": "com_5566778899", "comment_type": "main", "content": "@小丸子 敏感肌能用吗?", "create_time_stamp": 1744291200, "create_time": "2025-06-10 16:13:20", "like_count": 45, "reply_count": 0, "is_top": false, "user_info": { "user_id": "u_789ghi123", "nickname": "护肤小白日常", "avatar": "https://sns-avatar-qc.xhscdn.com/avatar/ghi789.jpg" }, "sub_comments": [] } ] }
五、核心解析实战要点
- 时间格式化:
create_time时间戳统一转为标准日期字符串,便于按日 / 月做评论量统计; - 父子评论绑定:子评论新增
parent_comment_id字段,绑定所属主评论 ID,数据库关联查询; - 用户信息剥离:统一封装
user_info对象,适配用户画像库关联; - 空值容错:
sub_comments无回复时默认空数组,避免数组遍历空指针报错; - 分页闭环:保存返回
cursor,循环遍历至has_more=false完成全量评论抓取。
六、接口异常返回 JSON 示例(错误处理参考)
json
{ "code": 401, "msg": "access_token已过期,请重新授权", "request_id": "req_err_123456", "data": {} }
json
{ "code": 429, "msg": "接口调用超限,限流冷却10s", "request_id": "req_limit_789", "data": {} }
七、落地业务场景
- 品牌舆情监控:抓取评论关键词,统计好评 / 差评占比,分析产品痛点;
- 竞品数据分析:对标同品类笔记评论量、互动率,测算种草热度;
- 用户问答收集:筛选带价格、使用方法的评论,整理 FAQ 知识库。
八、精简 Python 解析代码(配套实战)
python
运行
import time def parse_xhs_comment(raw_json): res = {} resp_data = raw_json.get("data", {}) res["note_id"] = resp_data.get("note_id") res["total_comment"] = resp_data.get("total_comment",0) res["next_cursor"] = resp_data.get("cursor","") res["has_more"] = resp_data.get("has_more",False) main_list = [] #遍历主评论 for item in resp_data.get("comments",[]): main = { "comment_id":item["comment_id"], "comment_type":"main", "content":item["content"], "create_time_stamp":item["create_time"], "create_time":time.strftime("%Y-%m-%d %H:%M:%S",time.localtime(item["create_time"])), "like_count":item["like_count"], "reply_count":item["reply_count"], "is_top":item["is_top"], "user_info":item["user"], "sub_comments":[] } #解析子评论 subs = [] for sub in item.get("sub_comments",[]): sub_item = { "comment_id":sub["comment_id"], "comment_type":"sub", "parent_comment_id":main["comment_id"], "content":sub["content"], "create_time_stamp":sub["create_time"], "create_time":time.strftime("%Y-%m-%d %H:%M:%S",time.localtime(sub["create_time"])), "like_count":sub["like_count"], "reply_target_uid":sub.get("reply_user_id",""), "user_info":sub["user"] } subs.append(sub_item) main["sub_comments"] = subs main_list.append(main) res["main_comments"] = main_list return res