# 小红书详情模块 ## 快速开始 ### Python API(推荐) ```python from script.detail import get_xiaohongshu_detail # 获取笔记详情 detail = get_xiaohongshu_detail("68d62e4500000000130085fc") print(f"标题: {detail['title']}") print(f"正文: {detail['body_text']}") print(f"视频: {detail['video']}") print(f"类型: {detail['content_type']}") print(f"发布时间: {detail['publish_time']}") ``` ### 命令行工具 ```bash # 获取详情 python script/detail/xiaohongshu_detail.py --note-id "68d62e4500000000130085fc" # 强制刷新 python script/detail/xiaohongshu_detail.py --note-id "68d62e4500000000130085fc" --force ``` --- ## API 文档 ### 函数签名 ```python detail = get_xiaohongshu_detail( note_id: str, # 必填:笔记ID force=False # 可选:强制刷新(忽略缓存) ) ``` ### 返回值 ```python { "channel_content_id": "68d62e4500000000130085fc", "link": "https://www.xiaohongshu.com/explore/68d62e4500000000130085fc", "comment_count": null, "images": [ "http://res.cybertogether.net/crawler/image/bf6a0e92ed7252ae8414121edf26f2d3.jpeg" ], "like_count": 14, "body_text": "时隔两个月,终于有时间把穿越极圈的航拍视频剪辑出来了...", "title": "穿越北极圈,终生难忘", "collect_count": 6, "channel_account_id": "664954500000000007006ac0", "channel_account_name": "Colin SW", "content_type": "video", # 根据 video 字段自动判断 "video": "http://sns-video-hw.xhscdn.com/stream/1/110/258/...", "publish_timestamp": 1758877418000, "publish_time": "2025-09-26 17:03:38" } ``` ### 字段说明 | 字段 | 类型 | 说明 | |------|------|------| | channel_content_id | string/null | 笔记ID | | link | string/null | 笔记链接 | | title | string/null | 标题 | | body_text | string/null | 完整正文内容 | | channel_account_name | string/null | 作者名称 | | channel_account_id | string/null | 作者ID | | like_count | number/null | 点赞数 | | comment_count | number/null | 评论数 | | collect_count | number/null | 收藏数 | | images | array | 图片URL列表(已去重) | | video | string/null | 视频链接 | | content_type | string | 内容类型("video" 或 "normal") | | publish_timestamp | number/null | 发布时间戳(毫秒) | | publish_time | string/null | 发布时间(格式:YYYY-MM-DD HH:MM:SS) | **注意**: - 不存在的字段统一用 `null` 表示,而非空字符串或 0 - 图片已自动按顺序去重 - `content_type` 自动判断:有 `video` 字段时为 "video",否则为 "normal" --- ## 使用示例 ### 1. 基本使用 ```python from script.detail import get_xiaohongshu_detail # 获取笔记详情 detail = get_xiaohongshu_detail("68d62e4500000000130085fc") print(f"标题: {detail['title']}") print(f"正文: {detail['body_text']}") print(f"点赞: {detail['like_count']}") ``` ### 2. 强制刷新 ```python # 忽略缓存,重新请求 API detail = get_xiaohongshu_detail("68d62e4500000000130085fc", force=True) ``` ### 3. 判断内容类型 ```python detail = get_xiaohongshu_detail("68d62e4500000000130085fc") if detail['content_type'] == 'video': print(f"视频链接: {detail['video']}") else: print(f"图文笔记,图片数量: {len(detail['images'])}") ``` ### 4. 搜索 + 详情(完整流程) ```python from script.search import search_xiaohongshu from script.detail import get_xiaohongshu_detail # 1. 搜索笔记 search_result = search_xiaohongshu("产品测试", publish_time="一周内") # 2. 获取前 5 条的完整详情 for note in search_result['notes'][:5]: note_id = note['channel_content_id'] # 获取详情 detail = get_xiaohongshu_detail(note_id) print(f"\n标题: {detail['title']}") print(f"摘要: {note['desc'][:50]}...") # 搜索结果的摘要 print(f"完整正文: {detail['body_text'][:100]}...") # 详情的完整正文 print(f"点赞: {detail['like_count']}") print(f"类型: {detail['content_type']}") ``` ### 5. 批量获取详情 ```python note_ids = [ "68d62e4500000000130085fc", "68b69ea9000000001c035a4d", "6808c0e8000000001c00a771" ] for note_id in note_ids: try: detail = get_xiaohongshu_detail(note_id) print(f"✓ {detail['title']}") except Exception as e: print(f"✗ {note_id}: {e}") ``` --- ## 命令行使用 ### 基本使用 ```bash python script/detail/xiaohongshu_detail.py --note-id "68d62e4500000000130085fc" ``` ### 强制刷新 ```bash python script/detail/xiaohongshu_detail.py --note-id "68d62e4500000000130085fc" --force ``` ### 禁用缓存 ```bash python script/detail/xiaohongshu_detail.py --note-id "68d62e4500000000130085fc" --no-cache ``` ### 完整参数 | 参数 | 默认值 | 说明 | |------|--------|------| | --note-id | 必填 | 笔记ID | | --force | False | 强制刷新(忽略缓存) | | --no-cache | False | 禁用缓存功能 | | --results-dir | data/detail | 输出目录 | | --timeout | 30 | 超时时间(秒) | | --max-retries | 5 | 最大重试次数 | | --retry-delay | 2 | 重试延迟(秒) | --- ## 核心特性 ### 1. 自动缓存(默认开启) 相同的笔记 ID 会自动使用缓存: ```python # 第一次:请求 API detail1 = get_xiaohongshu_detail("68d62e4500000000130085fc") # 第二次:使用缓存(瞬间返回) detail2 = get_xiaohongshu_detail("68d62e4500000000130085fc") # 强制刷新 detail3 = get_xiaohongshu_detail("68d62e4500000000130085fc", force=True) ``` ### 2. 自动重试(失败重试 5 次) - 超时错误:自动重试 - 连接错误:自动重试 - 5xx 服务器错误:自动重试 - 4xx 客户端错误:不重试 - API 返回失败(success=false):自动重试 指数退避策略:2秒 → 4秒 → 8秒 → 16秒 → 32秒 ### 3. 自动保存(后台完成) 详情结果自动保存到 `data/detail/xiaohongshu_detail/` 目录结构: ``` data/detail/xiaohongshu_detail/ └── {note_id}/ ├── raw/ # 原始数据(完整 API 响应) │ └── {timestamp}.json └── clean/ # 清洗数据(扁平化结构) └── {timestamp}.json ``` 文件名示例: - `20251113_144230.json` **注意**: 只有新请求的数据才会保存,使用缓存时不会重复保存文件。 ### 4. 图片自动去重 图片 URL 会自动按顺序去重: ```python # 原始数据可能有重复 # images: ["url1", "url1", "url2"] # 返回的数据已去重 # images: ["url1", "url2"] ``` ### 5. Content Type 自动判断 根据 `video` 字段自动判断内容类型: ```python # 有视频 detail['video'] = "http://..." detail['content_type'] = "video" # 无视频 detail['video'] = null detail['content_type'] = "normal" ``` ### 6. 时间自动转换 自动将时间戳转换为可读格式: ```python detail['publish_timestamp'] = 1758877418000 # 毫秒时间戳 detail['publish_time'] = "2025-09-26 17:03:38" # 格式化时间 ``` --- ## 数据格式 ### Clean 数据(推荐使用) ```json { "channel_content_id": "68d62e4500000000130085fc", "link": "https://www.xiaohongshu.com/explore/68d62e4500000000130085fc", "comment_count": null, "images": [ "http://res.cybertogether.net/crawler/image/bf6a0e92ed7252ae8414121edf26f2d3.jpeg" ], "like_count": 14, "body_text": "完整正文内容...", "title": "穿越北极圈,终生难忘", "collect_count": 6, "channel_account_id": "664954500000000007006ac0", "channel_account_name": "Colin SW", "content_type": "video", "video": "http://sns-video-hw.xhscdn.com/...", "publish_timestamp": 1758877418000, "publish_time": "2025-09-26 17:03:38" } ``` ### Raw 数据 完整的 API 响应,包含所有元数据和嵌套结构: ```json { "note_id": "68d62e4500000000130085fc", "timestamp": "20251113_144230", "api_response": { "success": true, "result": [...], "tool_name": "get_xhs_detail_by_note_id", "call_type": "api" } } ``` --- ## 常见问题 ### Q: 缓存如何清理? A: - 方式1:手动删除 `data/detail/xiaohongshu_detail/{note_id}/` 目录 - 方式2:使用 `force=True` 参数强制刷新 ### Q: 如何判断是否使用了缓存? A: 看控制台输出: - 使用缓存:`✓ 使用缓存数据: ...` - 请求 API:`正在获取笔记详情: ... (尝试 1/5)` ### Q: video 字段为什么有时是 null? A: - 搜索接口不返回 video 字段 - 详情接口会返回 video 字段(如果笔记有视频的话) - 图文笔记没有视频,video 字段为 null ### Q: comment_count 为什么是 null? A: API 返回的数据中,某些字段可能不存在或为 null,我们保持原样返回,不会强制转换为 0。 ### Q: content_type 如何判断? A: - 自动判断:有 `video` 字段(非 null)时为 "video" - 否则为 "normal"(图文笔记) --- ## 技术细节 ### 内部默认配置 - **超时时间**:30 秒 - **最大重试**:5 次 - **重试延迟**:2 秒(指数增长) - **缓存开关**:默认开启 - **输出目录**:`data/detail` ### 缓存机制 - 基于笔记 ID 生成缓存目录 - 按文件修改时间排序,返回最新文件 - 只有新请求成功后才保存缓存 ### API 成功验证 只有当 API 返回 `success: true` 时才视为成功并保存缓存,否则会继续重试。 --- ## 与搜索模块配合使用 详情模块通常与搜索模块配合使用: ```python from script.search import search_xiaohongshu from script.detail import get_xiaohongshu_detail # 1. 搜索笔记(获取摘要) search_result = search_xiaohongshu("产品测试") # 2. 对感兴趣的笔记获取详情(获取完整正文和视频) for note in search_result['notes'][:5]: note_id = note['channel_content_id'] detail = get_xiaohongshu_detail(note_id) # 搜索结果的摘要 print(f"摘要: {note['desc']}") # 详情的完整正文 print(f"完整正文: {detail['body_text']}") # 视频(如果有) if detail['video']: print(f"视频: {detail['video']}") ``` **关键区别**: - 搜索接口:返回摘要(`desc`),不返回 `body_text` 和 `video` - 详情接口:返回完整正文(`body_text`)和视频链接(`video`)