技能创建器
skill-creator
创建、改进和评估自定义技能,把专业流程转化为可重复使用的 AI 能力。
xiaohongshu-hub【数据与研究】Skill for reading and writing Xiaohongshu (XHS) data using Python + UV. It depends only on httpx + pycryptodome, automatically retrieves cookies via `browser_use get_cookies` to complete authentication, and requires no manual copying. It supports searching notes, users, and topics; reading note details and comments; recommendation feeds; trending lis…
独立 GitHub 快照 · 自动分类 · 以原作者文档为准
browser_use get_cookies to complete authentication, and requires no manual copying.
It supports searching notes, users, and topics; reading note details and comments; recommendation feeds; trending lists;
social actions (follow/favorite); interactions (like/comment/reply); notification queries; creator note management; and more.
This skill must be triggered when the user mentions "Xiaohongshu," "XHS," "scraping Xiaohongshu," "searching Xiaohongshu notes," "Xiaohongshu comments,"
"xiaohongshu-hub," "reading Xiaohongshu data," "Xiaohongshu Cookie,"
or any scenario that requires programmatically reading or writing Xiaohongshu content.Modified from: jackwener/xiaohongshu-cli (Apache-2.0)
This skill simplifies and modifies the original repository as follows:
- Removes the
browser-cookie3/click/rich/PyYAML/qrcodedependencies- Changes Cookie authentication to pass a
dictdirectly or read from environment variables, without automatic browser extraction- Removes the CLI layer (
commands/) and QR login module (qr_login.py)- Keeps the complete reverse-engineered signing algorithm in
signing.py, implemented with the standard library only and no third-party dependencies- Keeps AES-128-CBC signing in
creator_signing.py(depends on pycryptodome)- In the Minis environment, cookies are automatically retrieved through
browser_use get_cookies
/var/minis/skills/xiaohongshu-hub/
├── SKILL.md
├── pyproject.toml # UV project configuration (httpx + pycryptodome only)
└── scripts/
├── __init__.py
├── constants.py # Constants (Host, UA, SDK version, etc.)
├── exceptions.py # Structured exceptions (6 error types)
├── signing.py # Main API signing (x-s / x-s-common / x-t), standard library only
├── creator_signing.py # Creator API signing (AES-128-CBC)
└── client.py # XhsClient core class (all API methods)
The Xiaohongshu Web API uses three key cookies:
| Cookie | Description |
|---|---|
a1 | User identity identifier and core signing algorithm parameter (required) |
web_session | Login session (required) |
webId | Device ID (recommended) |
browser_use (Preferred in the Minis Environment)In Minis, you can use the browser_use tool to navigate to Xiaohongshu, then use get_cookies to read the cookies automatically.
Raw Cookie values will not appear in the conversation. They are passed securely through an offload env file.
Steps:
browser_use navigate to open https://www.xiaohongshu.com and confirm that you are logged in.browser_use get_cookies to retrieve a1, web_session, and webId separately.
/var/minis/offloads/env_cookies_xxx.sh.. /var/minis/offloads/env_cookies_xxx.sh
# The file exports variables such as COOKIE_A1 / COOKIE_WEB_SESSION / COOKIE_WEBID
export XHS_A1="$COOKIE_A1"
export XHS_WEB_SESSION="$COOKIE_WEB_SESSION"
export XHS_WEBID="$COOKIE_WEBID"
Note:
get_cookiesonly applies to the current page's domain. Navigate tohttps://www.xiaohongshu.combefore calling it.
https://www.xiaohongshu.com.a1, web_session, and webId.XHS_A1 / XHS_WEB_SESSION / XHS_WEBID.XHS_A1 + XHS_WEB_SESSION + XHS_WEBID (recommended)XhsClient({"a1": ..., "web_session": ..., "webId": ...})-a1 / --web-sessioncd /var/minis/skills/xiaohongshu-hub
uv sync
import os, json, sys
sys.path.insert(0, "/var/minis/skills/xiaohongshu-hub")
from scripts.client import XhsClient
# Method 1: Build from environment variables (recommended)
client = XhsClient.from_env()
# Method 2: Pass a Cookie dict directly
client = XhsClient({
"a1": os.environ["XHS_A1"],
"web_session": os.environ["XHS_WEB_SESSION"],
"webId": os.environ["XHS_WEBID"],
})
with client:
# Current user information
me = client.get_self_info()
print("User:", me.get("nickname"))
# Search notes
results = client.search_notes("Food", page=1)
for item in results.get("items", [])[:5]:
note = item.get("note_card", {})
print(f" - {note.get('display_title', '')}")
# Recommendation feed
feed = client.get_home_feed()
print(f"Recommendation feed: {len(feed.get('items', []))} items")
# Trending notes (travel)
hot = client.get_hot_feed("homefeed.travel_v3")
print(f"Trending travel: {len(hot.get('items', []))} items")
# Search notes and output JSON
cd /var/minis/skills/xiaohongshu-hub
uv run python -c "
import os, json, sys
sys.path.insert(0, '.')
from scripts.client import XhsClient
with XhsClient.from_env() as c:
r = c.search_notes('Travel', page=1)
print(json.dumps(r, ensure_ascii=False, indent=2))
"
# Get current user information
uv run python -c "
import os, json, sys
sys.path.insert(0, '.')
from scripts.client import XhsClient
with XhsClient.from_env() as c:
print(json.dumps(c.get_self_info(), ensure_ascii=False, indent=2))
"
| Method | Description |
|---|---|
get_self_info() | Get information about the currently logged-in user |
get_user_info(user_id) | Get profile information for a specified user |
get_user_notes(user_id, cursor="") | Get a list of notes posted by a user |
| Method | Description |
|---|---|
search_notes(keyword, page=1, sort="general", note_type=0) | Search notes |
search_users(keyword, page=1) | Search users |
search_topics(keyword) | Search topics/tags |
sort options: "general" / "popularity_descending" / "time_descending"
note_type options: 0 = all / 1 = video / 2 = image and text
| Method | Description |
|---|---|
get_note_by_id(note_id, xsec_token="") | Get note details |
get_comments(note_id, cursor="", xsec_token="") | Get comments (single page) |
get_all_comments(note_id, xsec_token="", max_pages=20) | Automatically page through and get all comments |
get_sub_comments(note_id, comment_id, cursor="", xsec_token="") | Get comment replies |
| Method | Description |
|---|---|
get_home_feed(category="homefeed_recommend") | Recommendation feed |
get_hot_feed(category="homefeed.food_v3") | Trending notes (by category) |
Trending categories: fashion_v3 / food_v3 / cosmetics_v3 / movie_and_tv_v3 /
career_v3 / love_v3 / household_product_v3 / gaming_v3 / travel_v3 / fitness_v3
| Method | Description |
|---|---|
follow_user(user_id) | Follow a user |
unfollow_user(user_id) | Unfollow |
get_user_favorites(user_id, cursor="") | Get a user's favorites |
| Method | Description |
|---|---|
like_note(note_id, xsec_token="") | Like |
unlike_note(note_id, xsec_token="") | Unlike |
collect_note(note_id, xsec_token="") | Favorite |
uncollect_note(note_id, xsec_token="") | Unfavorite |
post_comment(note_id, content, xsec_token="") | Post a comment |
reply_comment(note_id, comment_id, content, xsec_token="") | Reply to a comment |
delete_comment(note_id, comment_id) | Delete your own comment |
| Method | Description |
|---|---|
get_unread_count() | Number of unread notifications |
get_notifications_mentions(cursor="") | Comments / @ notifications |
get_notifications_likes(cursor="") | Like / favorite notifications |
get_notifications_connections(cursor="") | New follower notifications |
| Method | Description |
|---|---|
get_my_notes(page=0) | Get a list of notes you posted |
delete_note(note_id) | Delete a note (experimental) |
from scripts.exceptions import (
NeedVerifyError, # CAPTCHA triggered (HTTP 461/471)
SessionExpiredError, # Cookie expired (code -100)
IpBlockedError, # IP blocked (code 300012)
SignatureError, # Signing failed (code 300015)
XhsApiError, # Other API errors (base class)
)
try:
result = client.search_notes("Food")
except NeedVerifyError:
print("A CAPTCHA was triggered. Complete verification in the browser and try again.")
except SessionExpiredError:
print("Cookie has expired. Retrieve it again.")
except IpBlockedError:
print("IP is blocked. Switch networks.")
except XhsApiError as e:
print(f"API error: {e} (code={e.code})")
This skill inherits the complete anti-risk-control implementation from the original repository:
x-s / x-s-common / x-t signing (reverse-engineered from the web client)browser_use get_cookies.get_all_comments pages through up to 20 pages by default. You can adjust this with max_pages.