rednote-skills
Use this skill for Xiaohongshu workflows via a shared real Chrome profile: login, draft save, note search/export, profile note listing, and note interactions.
install
source · Clone the upstream repo
git clone https://github.com/Ubanillx/rednote-skills
Claude Code · Install into ~/.claude/skills/
git clone --depth=1 https://github.com/Ubanillx/rednote-skills ~/.claude/skills/ubanillx-rednote-skills-rednote-skills
manifest:
SKILL.mdsource content
rednote-skill
Directory structure
rednote-skills/ ├── scripts/ │ ├── _bootstrap_env.py # Venv bootstrap helper │ ├── action_delay.py # Delay/cooldown management │ ├── batch_context_comments.py # Batch comment sending with context │ ├── batch_dump_notes.py # Batch export note data (JSON+XLSX) from URL list │ ├── batch_generate_comment_materials.py # Generate comment materials from search │ ├── batch_search_keywords.py # Batch keyword search │ ├── browser_profile.py # Chrome profile management │ ├── collect_note.py # Collect/bookmark notes │ ├── comment_note.py # Send comments to notes │ ├── convert_notes_to_xlsx.py # Convert JSON notes to styled Excel (no browser) │ ├── dedupe_utils.py # Shared deduplication utilities │ ├── dedup_urls.py # Deduplicate URLs against index (no browser) │ ├── dump_note.py # Export single note (markdown or JSON) │ ├── export_profile_note_comments.py # Export profile note comments to Excel/JSON │ ├── follow_user.py # Follow users │ ├── interact_helpers.py # Helper functions for interactions │ ├── like_note.py # Like notes │ ├── list_profile_notes.py # List notes from a user profile │ ├── manual_login.py # Manual login helper │ ├── note_content.py # Note content extraction utilities │ ├── official_risk_guard.py # Risk detection and guard │ ├── publish_note.py # Save notes as drafts │ ├── search_note_by_key_word.py # Search notes by keyword │ └── validate_cookies.py # Cookie/login validation ├── deliveries/ # Final deliverables ├── logs/rednote/ # Runtime logs and dedupe indexes ├── tmp/rednote/ # Temporary or debug files ├── SKILL.md # This file ├── README.md # Project documentation └── requirements.txt # Python dependencies
Script naming conventions
— Batch operations that process multiple items (e.g.,batch_<action>_<target>.py
,batch_dump_notes.py
)batch_search_keywords.py
— Single-item operations (e.g.,<action>_<target>.py
,dump_note.py
,like_note.py
)search_note_by_key_word.py
— Shared utility modules (e.g.,<descriptor>_utils.py
)dedupe_utils.py
— Format conversion scripts (e.g.,<action>_<target>_to_<format>.py
)convert_notes_to_xlsx.py
Browser scripts launch Chrome; pure data scripts (dedup_urls, convert_notes_to_xlsx) do not.
Core rules
- Use the shared real Chrome profile through Patchright. Do not switch to a temporary cookie browser.
- Start with the target business script. Do not force
first.validate_cookies.py - If a script says
or asks for未登录小红书
, complete manual login and rerun the same script.python3 scripts/manual_login.py - Search, dump, publish, like, collect, follow, and comment must all reuse the same Chrome profile.
- For comment or reply workflows, read the note first, then let AI write the final article-specific text, then send it.
- Never ask Python to rewrite or generate comments.
only sends the final text you pass in.comment_note.py
Browser config
Default values:
- Chrome executable: auto-detected
- Chrome source user data dir:
~/Library/Application Support/Google/Chrome - Chrome runtime user data dir:
workspace tmp/rednote/chrome-user-data - Chrome profile directory:
Profile 2
Optional overrides:
REDNOTE_CHROME_PATHREDNOTE_CHROME_USER_DATA_DIRREDNOTE_CHROME_RUNTIME_USER_DATA_DIRREDNOTE_CHROME_PROFILE_DIRECTORY
File creation rules
Directory rules:
- Put final deliverables under
deliveries/ - Put runtime logs under
logs/rednote/ - Put temporary or debug files under
tmp/rednote/ - Do not create business output files under
orskills/scripts/
File type rules:
- Use
for structured machine-readable input or output.json - Use
for append-only process logs.jsonl - Use
or.csv
for human review and spreadsheet delivery.xlsx - Use
for summaries, handoff notes, or run instructions.md
Naming rules:
- Prefer lowercase snake_case for stable filenames
- Prefer
for run-level timestamps, for exampleYYYYMMDDTHHMMSS20260403T153000.json - Prefer
,batch_01_<keyword>.json
,combined_50.json
for task outputs when a batch structure existssummary.json - Keep names ASCII when practical; if a Chinese keyword is business-critical, keep it short and stable
Creation rules:
- Default to creating a new timestamped file instead of overwriting an old result
- Only append to log files such as
logs/rednote/*.jsonl - Only overwrite an existing file when the command explicitly targets that path and replacement is intentional
- When a task creates a delivery folder, add a short
if the folder contains multiple result filesREADME.md
Path rules:
- Prefer absolute paths for
,--input
, and--output--output-dir - Reuse script default output paths unless the task needs a dedicated delivery folder
- Preserve note URLs exactly when saving records, including
andxsec_tokenxsec_source
Recommended patterns:
- Batch materials:
logs/rednote/generated_comment_materials/<run_id>.json|csv|xlsx - Batch logs:
andlogs/rednote/batch_search_keywords.jsonllogs/rednote/batch_context_comments.jsonl - Profile exports:
deliveries/rednote_profile_comment_sheets/<run_id>.json|xlsx - Ad hoc note lists or debug data:
tmp/rednote/<topic>_<date>.json
Note dedupe rules
Goal:
- Avoid repeated note capture across runs
- Avoid collecting multiple notes from the same author in the same dedupe scope
- Keep dedupe state persistent and machine-readable
Default storage:
- Use
as the default persistent dedupe indexlogs/rednote/note_dedupe_index.json - If a task needs an isolated dedupe scope, pass a dedicated path with
--dedupe-path - Recommended isolated naming:
logs/rednote/note_dedupe_index_<topic>.json
How to save:
- Save dedupe state as JSON, not JSONL
- Keep one persistent index file per dedupe scope
- Write the dedupe index after a batch run finishes
- Do not mix unrelated campaigns into the same dedupe file unless cross-campaign dedupe is intended
Index shape:
- Top-level fields:
,version
,itemsauthors
is keyed byitemsnote_id
is keyed by normalizedauthorsauthor_key
Recommended item fields:
note_idauthor_nameauthor_keyfirst_seen_atlast_seen_atsource_keywordlast_run_idstatusdedupe_reason
Recommended author fields:
author_keyauthor_namefirst_seen_atlast_seen_atfirst_note_idlast_note_idsource_keywordlast_run_id
How to validate:
- Parse
from the candidate note URL before opening the detail pagenote_id - If
already exists in the persistent index or current-run memory set, skip early as a note duplicatenote_id - After reading note content, extract the authoritative
from note data and check againnote_id - Normalize author name into
and check author-level duplicationauthor_key - Only keep the note when both
andnote_id
pass validationauthor_key
Author normalization:
- Build
from cleaned author nicknameauthor_key - Normalize with NFKC
- Remove whitespace differences
- Compare case-insensitively
- Treat the normalized
as the stable author dedupe keyauthor_key
How to dedupe:
- First priority:
note_id - Second priority:
author_key - If
is duplicated, skip directlynote_id - If
is new butnote_id
already exists, skip asauthor_keyauthor_duplicate - Default policy is strict: one author contributes at most one captured note within one dedupe scope
How to record results:
- Captured notes: write to batch output and update dedupe index with
status: captured - Author duplicates found after content read: update dedupe index with
andstatus: skippeddedupe_reason: author_duplicate - Note duplicates detected before capture: count as skipped in run summary even if no new item is written
- Run summary should expose at least:
deduped_skippednote_id_skippedauthor_skippedcaptured
Operational rules:
- Never treat note title as a dedupe key
- Never treat keyword as a dedupe key
- Do not save records without a valid
into the persistent dedupe indexnote_id - Preserve the original note URL in exported records, including
andxsec_tokenxsec_source - If the business goal requires multiple notes from the same author, use a separate
for that task instead of reusing the default global index--dedupe-path
Login flow
Run the business script first. Only login when needed.
cd rednote-skills python3 scripts/manual_login.py
Optional check:
cd rednote-skills python3 scripts/validate_cookies.py
: already logged inTrue
: runFalsepython3 scripts/manual_login.py
Common commands
cd rednote-skills # Draft save only python3 scripts/publish_note.py python3 scripts/publish_note.py "测试标题" "正文内容" --delay-seconds 5 python3 scripts/publish_note.py "测试|图文混排" $'第一段\n\n[[image:/absolute/path/to/a.jpg]]\n\n第二段' --delay-seconds 5 # Search / export python3 scripts/search_note_by_key_word.py "关键词" --top_n 5 --delay-seconds 3 python3 scripts/search_note_by_key_word.py "关键词" --start-index 21 --end-index 40 --filter '{"sort_by":"最新","note_type":"图文"}' --delay-seconds 3 python3 scripts/batch_search_keywords.py --input /absolute/path/to/keywords.json --top-n 5 --delay-seconds 3 python3 scripts/batch_generate_comment_materials.py --input /absolute/path/to/keywords.json --top-n 5 --delay-seconds 3 --dedupe-path logs/rednote/note_dedupe_index.json python3 scripts/list_profile_notes.py --profile-url "https://www.xiaohongshu.com/user/profile/<user_id>" --output /absolute/path/to/profile_notes.json python3 scripts/list_profile_notes.py --user-id "<user_id>" --limit 0 --delay-seconds 3 python3 scripts/dump_note.py "<note_url>" python3 scripts/dump_note.py "<note_url>" --format json python3 scripts/dump_note.py "<note_url>" --format json --output /absolute/path/to/note.json # Deduplicate URLs (pure data, no browser) python3 scripts/dedup_urls.py --input /absolute/path/to/urls.json --output /absolute/path/to/unique_urls.json python3 scripts/dedup_urls.py --input /absolute/path/to/urls.json --dedupe-path logs/rednote/note_dedupe_index_<topic>.json --update-index python3 scripts/dedup_urls.py --input /absolute/path/to/urls.json --dry-run # Batch export notes (browser required) python3 scripts/batch_dump_notes.py --input /absolute/path/to/urls.json --output-dir deliveries/bid_notes --dedupe-path logs/rednote/note_dedupe_index.json --limit 30 --delay-seconds 3 python3 scripts/batch_dump_notes.py --input /absolute/path/to/urls.json --dry-run # Convert JSON notes to Excel (pure data, no browser) python3 scripts/convert_notes_to_xlsx.py --input /absolute/path/to/notes.json --output /absolute/path/to/summary.xlsx python3 scripts/convert_notes_to_xlsx.py --input /absolute/path/to/notes.json --output /absolute/path/to/summary.xlsx --columns "title,nickname,note_url,tags,desc,publish_time,liked_count" # Export profile note comments python3 scripts/export_profile_note_comments.py --profile-url "https://www.xiaohongshu.com/user/profile/<user_id>" --output-dir deliveries/rednote_profile_comment_sheets python3 scripts/export_profile_note_comments.py --input /absolute/path/to/profile_notes.json --limit 10 # Interactions python3 scripts/like_note.py "<note_url>" --delay-seconds 5 python3 scripts/collect_note.py "<note_url>" --delay-seconds 5 python3 scripts/follow_user.py "<note_url>" --delay-seconds 5 python3 scripts/comment_note.py "<note_url>" "<final_comment>" --delay-seconds 5 --like-probability 0.35 python3 scripts/batch_context_comments.py --input /absolute/path/to/comments.json --delay-seconds 5 --like-probability 0.35
Publish rules
saves to drafts only. It does not publish.publish_note.py- Body supports inline image placeholders:
[[image:/absolute/path/to/file]] - Keep image paths absolute for reliability.
- The browser stays open after draft save for manual review.
Search rules
returns a Python list of note URLs.search_note_by_key_word.py- Use
for the first N results.--top_n - Use
and--start-index
for waterfall ranges.--end-index - Use
and--max-scroll-rounds
when you need a deeper range.--max-idle-scroll-rounds
supports:--filter '<json>'
:sort_by
/综合
/最新
/最多点赞
/最多评论最多收藏
:note_type
/不限
/视频图文
:publish_time
/不限
/一天内
/一周内半年内
:search_scope
/不限
/已看过
/未看过已关注
:position_distance
/不限
/同城附近
- Filter aliases also work:
,sort
,location_distance
,location
,排序方式
,笔记类型
,发布时间
,搜索范围位置距离 - Preserve
andxsec_token
in note URLs for follow-up scripts.xsec_source
Profile note listing
accepts eitherlist_profile_notes.py
or--profile-url--user-id
means collect as many notes as the page exposes--limit 0- Output JSON includes
,profile_url
, andcountnotes - Each note includes
,id
,xsec_token
,xsec_source
,note_url
,titlecover
Batch search input
batch_search_keywords.py supports:
- JSON array of keywords:
["关键词A", "关键词B"] - JSON array of objects:
[{"keyword": "关键词A", "top_n": 5}] - JSON object with
:items{"items": [{"keyword": "关键词A", "top_n": 5}]} - JSON mapping:
{"关键词A": 5, "关键词B": {"top_n": 8}}
Per item fields:
keywordtop_nstart_indexend_indexmax_scroll_roundsmax_idle_scroll_roundsdelay_secondsfiltermeta
Rules:
- CLI
is supported--filter - Root-level
is supported forfilter
input{"items": [...]} - Merge order: CLI
< root--filter
< itemfilterfilter - Use
to validate input without launching searches--dry-run - Logs default to
logs/rednote/batch_search_keywords.jsonl
Comment workflow
Required order:
- Run
python3 scripts/dump_note.py "<note_url>" - Let AI write the final comment based on the actual note content
- Run
python3 scripts/comment_note.py "<note_url>" "<final_comment>" --delay-seconds 5
Hard rules:
- Never send generic template comments.
- Comments must be grounded in the current note's title,正文细节、标签、表达方式、情绪或观点.
- Reply comments must also be article-specific and consistent with the original comment context.
only sends the final comment text it receives.comment_note.py
or--like-probability <0-1>
controls optional pre-like behavior. Default:REDNOTE_COMMENT_AUTO_LIKE_PROBABILITY0.35
Batch comment workflow
Required order:
- Run
python3 scripts/batch_generate_comment_materials.py ... - Let AI read the exported materials and prepare
/absolute/path/to/comments.json - Run
python3 scripts/batch_context_comments.py --input /absolute/path/to/comments.json --delay-seconds 5 --like-probability 0.35
Rules:
only exports materials. It does not send comments.batch_generate_comment_materials.py- Exported files default to
logs/rednote/generated_comment_materials/<run_id>.json|csv|xlsx
andcomment_info
are placeholders for later AI-written draftsreply_comment_info
does not search notes or generate copybatch_context_comments.py- Each record must map one
to one finalnote_urlcomment_text - Do not batch-send generic praise or filler copy
- Use
to validate input without posting--dry-run - Logs default to
logs/rednote/batch_context_comments.jsonl
Supported
comments.json forms:
- JSON array:
[{"note_url": "...", "comment_text": "..."}] - JSON object with
:items{"items": [{"note_url": "...", "comment_text": "..."}]} - JSON mapping:
{"https://.../explore/...": "评论内容"}
Optional per-row fields:
delay_secondslike_probabilitymeta
Delay rules
- Sensitive scripts accept
--delay-seconds <seconds> - Shared default delay can be set with
REDNOTE_ACTION_DELAY_SECONDS - Random delay range can be adjusted with:
REDNOTE_RANDOM_DELAY_MIN_SECONDSREDNOTE_RANDOM_DELAY_MAX_SECONDS
Notes
- The search script can bootstrap the skill-local virtualenv automatically.
- If a note needs candidate images, use the sibling skill
first.skills/rednote-image-search