SuperAPI AI Directory

xhs

Writing & research

View repository

Updated 10-15 17:33

About this skill

The user wants to extract Xiaohongshu post content. Please proceed as follows:

Constant definitions

  • Cookies file: ~/cookies.json(Xiaohongshu cookies exported from Chrome)
  • Obsidian save directory: ~/Documents/Obsidian Vault/xhs
  • Whisper model: mlx-community/whisper-large-v3-turbo

Input

Xiaohongshu link provided by the user: $ARGUMENTS

Extraction process

Step 0: Check Cookies

  1. Check whether ~/cookies.json exists
  2. If it does not exist, inform the user that cookies need to be exported from Chrome:
    • Open xiaohongshu.com in Chrome and confirm that you are logged in
    • Open the DevTools Console and run the following code to copy the cookies to the clipboard:
    copy(JSON.stringify(document.cookie.split('; ').map(c => {
      const [name, ...rest] = c.split('=');
      return { name, value: rest.join('='), domain: '.xiaohongshu.com', path: '/',
        expires: Date.now()/1000 + 86400*30, size: name.length + rest.join('=').length,
        httpOnly: false, secure: false, session: false, priority: 'Medium',
        sameParty: false, sourceScheme: 'Secure', sourcePort: 443 };
    })))
    
    • Save the clipboard contents to ~/cookies.json
    • Then terminate the process and wait for the user to finish before running it again

Step 1: Parse the link

Extract the post ID (a 24-character hexadecimal string) and the xsec_token parameter from the URL.

Step 2: Get the post content

Use a Python script to request the post page HTML with the Cookies, and parse all post data from window.__INITIAL_STATE__ :

import json, urllib.request, ssl, re

with open('<Cookies 文件>') as f:
    cookies = json.load(f)
cookie_str = '; '.join(f"{c['name']}={c['value']}" for c in cookies)

ctx = ssl.create_default_context()
ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_NONE

req = urllib.request.Request('<帖子URL>')
req.add_header('Cookie', cookie_str)
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')

resp = urllib.request.urlopen(req, timeout=15, context=ctx)
html = resp.read().decode('utf-8', errors='ignore')

m = re.search(r'window\.__INITIAL_STATE__\s*=\s*(\{.+?\})\s*</script>', html, re.DOTALL)
raw = m.group(1).replace('undefined', 'null')
data = json.loads(raw)

# 帖子数据在: data['note']['noteDetailMap'][<key>]['note']
# 包含: title, desc, type, time, user, imageList, video, interactInfo, ipLocation

If the request fails (redirected to a 404/error page), it means the cookies have expired; prompt the user to re-export them as in Step 0.

Step 3: Video content extraction (video posts only)

If the post type is video,prefer the platform's embedded subtitles, and fall back to local Whisper transcription only when there are no subtitles.

3a. Check platform subtitles (preferred)

From the video data obtained in Step 2, check whether there are embedded subtitles:

note['video']['media'] 或 note['video']['mediaV2'](JSON 字符串,需二次解析)
-> 查找 subtitles 字段
-> 优先级:source > zh-CN > en-US
-> 取对应语言的 SRT URL

If a subtitle URL is found:

# 注意:字幕 CDN 域名必须使用 HTTPS(HTTP 可能超时)
curl -sL --connect-timeout 10 -o /tmp/xhs_{post_id}.srt \
  -H "User-Agent: Mozilla/5.0" \
  -H "Referer: https://www.xiaohongshu.com/" \
  "<字幕URL(确保 https://)>"

Parse the SRT file, merge it into continuous text (removing timestamps and sequence numbers), and reorganize it into paragraphs by semantic sentence breaks. Subtitles are more accurate than Whisper transcription, and there is no need to download the video,so they should be preferred。

3b. Whisper transcription (fallback)

Only when no subtitles are found in Step 3a, perform the following substeps:

Extract the video URL:

note['video']['media']['stream'] -> 按 h264 > h265 > av1 优先级取第一个的 masterUrl

Download the video and extract the audio:

curl -L -o /tmp/xhs_{post_id}.mp4 -H "Referer: https://www.xiaohongshu.com/" <视频URL>
ffmpeg -y -i /tmp/xhs_{post_id}.mp4 -vn -acodec pcm_s16le -ar 16000 -ac 1 /tmp/xhs_{post_id}.wav

Speech transcription:

import mlx_whisper
result = mlx_whisper.transcribe("/tmp/xhs_{post_id}.wav",
    path_or_hf_repo="mlx-community/whisper-large-v3-turbo", language="zh", verbose=False)

3c. Clean up the transcription/subtitle text

  • Remove repeated trailing characters (background music noise)
  • Break sentences semantically, add punctuation and paragraphs
  • If there is a step/key point structure, format it with Markdown

3d. Clean up temporary files

rm -f /tmp/xhs_{post_id}.mp4 /tmp/xhs_{post_id}.wav /tmp/xhs_{post_id}.srt

Step 3B: Image text recognition (image-text posts only)

If the post type is normal (an image-text post), and the images may contain a large amount of text content (such as long-form article screenshots, photos of PPT slides, infographics, etc.), perform the following substeps for OCR recognition.

Determine whether OCR is needed: If the post desc already contains the complete article content (more than 500 characters), OCR is usually not needed. But if desc is relatively short (such as only a title or a few introductory sentences), while the number of images is large (≥3), then the images are very likely the medium of the article and OCR extraction is needed.

3B-a. Download images

From the imageList obtained in Step 2, extract each image's urlDefault URL。

Key: the HTTP URL must be changed to HTTPS(HTTP connections to the Xiaohongshu image CDN may time out).

Batch download using curl:

# 单张下载
curl -sL --connect-timeout 10 -o /tmp/xhs_{post_id}_img_{序号}.jpg \
  -H "Referer: https://www.xiaohongshu.com/" \
  -H "User-Agent: Mozilla/5.0" \
  "<图片URL(http:// 替换为 https://)>"

# 批量下载(curl 多输出模式,一条命令下载所有图片)
curl -sL --connect-timeout 10 \
  -H "Referer: https://www.xiaohongshu.com/" \
  -H "User-Agent: Mozilla/5.0" \
  -o /tmp/xhs_{post_id}_img_00.jpg "<URL_0>" \
  -o /tmp/xhs_{post_id}_img_01.jpg "<URL_1>" \
  ...

3B-b. Read text from images

Use Claude Code's Read tool to read each image (multimodal capability, directly recognizing text in images).

Note the multi-image limit: Claude's multi-image context limit is a maximum side length of ≤ 2000px per image. A maximum of 4 images can be read simultaneously each time; if there are more than 4, they need to be read in batches.

# 分批读取,每批最多 4 张
Read /tmp/xhs_{post_id}_img_00.jpg
Read /tmp/xhs_{post_id}_img_01.jpg
Read /tmp/xhs_{post_id}_img_02.jpg
Read /tmp/xhs_{post_id}_img_03.jpg
# (下一批)
Read /tmp/xhs_{post_id}_img_04.jpg
...

Extract all Chinese/English text content from each image, and concatenate them in image order into a complete article.

3B-c. Organize the OCR text

  • Merge the text from all images into a continuous article
  • Fix sentence breaks across images (the last line of the previous image may be the same sentence as the first line of the next image)
  • Divide into sections according to logical structure and add subheadings
  • Preserve key data, quotations, and conclusions

3B-d. Clean up temporary files

rm -f /tmp/xhs_{post_id}_img_*.jpg

Step 4: Organize the output and save it

Organize the content into a Markdown file and save it to <Obsidian 保存目录>/{YYYY-MM-DD} {短标题}.md。

  • Filename format:{发布日期} {短标题}.md, the short title should not exceed 15 characters and is a minimalist summary of the core insight
  • The date prefix ensures chronological sorting
  • Do not create subdirectories; place all post md files directly under the xhs folder
  • Place media files uniformly in <Obsidian 保存目录>/img/ or <Obsidian 保存目录>/video/

Writing style: Peter Thiel style—direct, counterintuitive, give a judgment in one sentence. Notes are decision-making tools, not a knowledge base. Users can decide at a glance: dig deeper or skip.

File structure (no YAML frontmatter):

# 一句话核心洞察(反直觉的判断,不是描述性标题)

核心论点,2-3句话。直接给出"大多数人觉得X,但其实Y"的判断。
不废话,不铺垫,像 Thiel 在董事会上说话。

**与我的关联:** 一句话。读取用户的 memory(~/.claude/projects/*/memory/ 下的
user 和 project 类型记忆)了解用户背景、研究方向和当前工作,据此说清楚
这个内容跟用户有什么关系。如果 memory 不可用,从通用的个人发展/工具/方法论角度切入。

**值得深挖吗:** 是/否。一句话理由。

> [!tip]- 详情
> 帖子核心内容的结构化整理(折叠状态,点开才看到):
> - 从 desc、视频字幕/转录、图片 OCR 文字中提炼,清理 `#xxx[话题]#` 标记
> - 按逻辑结构分节,保留关键数据和结论
> - 纯装饰性图片用 `![图N](urlDefault)` 嵌入
> - 含大量文字的图片:嵌入 OCR 提取的结构化文本(不嵌入图片 URL)
> - 视频帖子在此处放整理后的字幕/转录内容

> [!info]- 笔记属性
> - **来源**: 小红书 · 作者名
> - **帖子ID**: xxx
> - **链接**: 原始链接
> - **日期**: YYYY-MM-DD
> - **类型**: image/video
> - **互动**: N赞 / N收藏 / N评论
> - **标签**: 标签1, 标签2, ...

Key constraints:

  • Visible content outside the collapsed areamust not exceed 6 lines
  • The title must be an insight/judgment, not a "summary of XX post"
  • Images use the URL in the urlDefault field