$npx -y skills add chenxiachan/xhs-claude-skills --skill xhs提取小红书帖子内容(文字、图片、视频转录),整理为 Markdown 并保存
| 1 | 用户希望提取小红书帖子内容。请按以下步骤处理: |
| 2 | |
| 3 | ## 常量定义 |
| 4 | - Cookies 文件: `~/cookies.json`(从 Chrome 导出的小红书 cookies) |
| 5 | - Obsidian 保存目录: `~/Documents/Obsidian Vault/xhs` |
| 6 | - Whisper 模型: `mlx-community/whisper-large-v3-turbo` |
| 7 | |
| 8 | ## 输入 |
| 9 | 用户提供的小红书链接: $ARGUMENTS |
| 10 | |
| 11 | ## 提取流程 |
| 12 | |
| 13 | ### 步骤 0:检查 Cookies |
| 14 | 1. 检查 `~/cookies.json` 是否存在 |
| 15 | 2. 如果不存在,告知用户需要从 Chrome 导出 cookies: |
| 16 | - 在 Chrome 打开 xiaohongshu.com 并确认已登录 |
| 17 | - 打开 DevTools Console,运行以下代码将 cookies 复制到剪贴板: |
| 18 | ```javascript |
| 19 | copy(JSON.stringify(document.cookie.split('; ').map(c => { |
| 20 | const [name, ...rest] = c.split('='); |
| 21 | return { name, value: rest.join('='), domain: '.xiaohongshu.com', path: '/', |
| 22 | expires: Date.now()/1000 + 86400*30, size: name.length + rest.join('=').length, |
| 23 | httpOnly: false, secure: false, session: false, priority: 'Medium', |
| 24 | sameParty: false, sourceScheme: 'Secure', sourcePort: 443 }; |
| 25 | }))) |
| 26 | ``` |
| 27 | - 将剪贴板内容保存到 `~/cookies.json` |
| 28 | - 然后终止流程,等用户完成后重新运行 |
| 29 | |
| 30 | ### 步骤 1:解析链接 |
| 31 | 从 URL 中提取帖子 ID(24 位十六进制字符串)和 xsec_token 参数。 |
| 32 | |
| 33 | ### 步骤 2:获取帖子内容 |
| 34 | 使用 Python 脚本,通过 Cookies 请求帖子页面 HTML,从 `window.__INITIAL_STATE__` 解析全部帖子数据: |
| 35 | |
| 36 | ```python |
| 37 | import json, urllib.request, ssl, re |
| 38 | |
| 39 | with open('<Cookies 文件>') as f: |
| 40 | cookies = json.load(f) |
| 41 | cookie_str = '; '.join(f"{c['name']}={c['value']}" for c in cookies) |
| 42 | |
| 43 | ctx = ssl.create_default_context() |
| 44 | ctx.check_hostname = False |
| 45 | ctx.verify_mode = ssl.CERT_NONE |
| 46 | |
| 47 | req = urllib.request.Request('<帖子URL>') |
| 48 | req.add_header('Cookie', cookie_str) |
| 49 | req.add_header('User-Agent', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36') |
| 50 | |
| 51 | resp = urllib.request.urlopen(req, timeout=15, context=ctx) |
| 52 | html = resp.read().decode('utf-8', errors='ignore') |
| 53 | |
| 54 | m = re.search(r'window\.__INITIAL_STATE__\s*=\s*(\{.+?\})\s*</script>', html, re.DOTALL) |
| 55 | raw = m.group(1).replace('undefined', 'null') |
| 56 | data = json.loads(raw) |
| 57 | |
| 58 | # 帖子数据在: data['note']['noteDetailMap'][<key>]['note'] |
| 59 | # 包含: title, desc, type, time, user, imageList, video, interactInfo, ipLocation |
| 60 | ``` |
| 61 | |
| 62 | 如果请求失败(被重定向到 404/错误页),说明 cookies 过期,提示用户按步骤 0 重新导出。 |
| 63 | |
| 64 | ### 步骤 3:视频转录(仅视频帖子) |
| 65 | 如果帖子 type 为 video,执行以下子步骤: |
| 66 | |
| 67 | #### 3a. 提取视频 URL |
| 68 | 从步骤 2 获取的数据中解析视频流: |
| 69 | ``` |
| 70 | note['video']['media']['stream'] -> 按 h264 > h265 > av1 优先级取第一个的 masterUrl |
| 71 | ``` |
| 72 | |
| 73 | #### 3b. 下载视频并提取音频 |
| 74 | ```bash |
| 75 | curl -L -o /tmp/xhs_{post_id}.mp4 -H "Referer: https://www.xiaohongshu.com/" <视频URL> |
| 76 | ffmpeg -y -i /tmp/xhs_{post_id}.mp4 -vn -acodec pcm_s16le -ar 16000 -ac 1 /tmp/xhs_{post_id}.wav |
| 77 | ``` |
| 78 | |
| 79 | #### 3c. 语音转录 |
| 80 | ```python |
| 81 | import mlx_whisper |
| 82 | result = mlx_whisper.transcribe("/tmp/xhs_{post_id}.wav", |
| 83 | path_or_hf_repo="mlx-community/whisper-large-v3-turbo", language="zh", verbose=False) |
| 84 | ``` |
| 85 | |
| 86 | #### 3d. 清理转录文本 |
| 87 | - 去除尾部重复字符(背景音乐噪音) |
| 88 | - 按语义断句,添加标点和段落 |
| 89 | - 如有步骤/要点结构,用 Markdown 格式化 |
| 90 | |
| 91 | #### 3e. 清理临时文件 |
| 92 | ```bash |
| 93 | rm -f /tmp/xhs_{post_id}.mp4 /tmp/xhs_{post_id}.wav |
| 94 | ``` |
| 95 | |
| 96 | ### 步骤 4:整理输出并保存 |
| 97 | 将内容整理为 Markdown 文件,保存到 `<Obsidian 保存目录>/{YYYY-MM-DD} {短标题}.md`。 |
| 98 | - 文件名格式:`{发布日期} {短标题}.md`,短标题不超过15个字,是核心洞察的极简概括 |
| 99 | - 日期前缀确保按时间排序 |
| 100 | - 不创建子目录,所有帖子 md 直接放在 xhs 文件夹下 |
| 101 | - 媒体文件统一放在 `<Obsidian 保存目录>/img/` 或 `<Obsidian 保存目录>/video/` |
| 102 | |
| 103 | **写作风格:Peter Thiel 式——直接、反直觉、一句话给判断。笔记是决策工具,不是知识库。用户扫一眼就能决定:深挖还是跳过。** |
| 104 | |
| 105 | 文件结构(**无 YAML frontmatter**): |
| 106 | |
| 107 | ```markdown |
| 108 | # 一句话核心洞察(反直觉的判断,不是描述性标题) |
| 109 | |
| 110 | 核心论点,2-3句话。直接给出"大多数人觉得X,但其实Y"的判断。 |
| 111 | 不废话,不铺垫,像 Thiel 在董事会上说话。 |
| 112 | |
| 113 | **与我的关联:** 一句话。读取用户的 memory(~/.claude/projects/*/memory/ 下的 |
| 114 | user 和 project 类型记忆)了解用户背景、研究方向和当前工作,据此说清楚 |
| 115 | 这个内容跟用户有什么关系。如果 memory 不可用,从通用的个人发展/工具/方法论角度切入。 |
| 116 | |
| 117 | **值得深挖吗:** 是/否。一句话理由。 |
| 118 | |
| 119 | > [!tip]- 详情 |
| 120 | > 帖子核心内容的结构化整理(折叠状态,点开才看到): |
| 121 | > - 从 desc 和视频转录中提炼,清理 `#xxx[话题]#` 标记 |
| 122 | > - 按逻辑结构分节,保留关键数据和结论 |
| 123 | > - 图片用 `` 嵌入 |
| 124 | > - 视频帖子在此处放整理后的转录内容 |
| 125 | |
| 126 | > [!info]- 笔记属性 |
| 127 | > - **来源**: 小红书 · 作者名 |
| 128 | > - **帖子ID**: xxx |
| 129 | > - **链接**: 原始链接 |
| 130 | > - **日期**: YYYY-MM-DD |
| 131 | > - **类型**: image/video |
| 132 | > - **互动**: N赞 / N收藏 / N评论 |
| 133 | > - **标签**: 标签1, 标签2, ... |
| 134 | ``` |
| 135 | |
| 136 | 关键约束: |
| 137 | - 折叠区域外的可见内容**不超过 6 行** |
| 138 | - 标题必须是洞察/判断,不是"XX帖子的总结" |
| 139 | - 图片使用 `urlDefault` 字段的 URL |