Install
openclaw skills install @6master6/xhs-content-creator小红书图文自动发布端到端 skill。流程:飞书 DM 收图 → agent 分析图片氛围 → 按「内容创作宪法」生成标题(≤20 字,关键词前置)/ 正文(300-800 字,3-5 段)/ 话题(2-5 个精准
openclaw skills install @6master6/xhs-content-creator把几张图变成一篇小红书笔记(草稿或真发)。本 skill 是端到端实现 — 收图、内容生成、协议转换、浏览器自动化发布,全在一个 skill 目录下。
~/.openclaw/media/inbound/,文件名形如 *.jpg)image 工具分析每张图(地点 / 氛围 / 主体 / 时间),输出 1-3 句氛围描述{emoji}{核心关键词}{|}{氛围短语},整段 ≤20 字(小红书规则,emoji 算 2 字符)。核心关键词前置便于搜索;避免标题党 / 极限词 / 夸张承诺(禁用词表见 §1.5 标题段)# 开头,多个用空格或换行分隔。组合维度:地点 + 氛围 + 季节 + 城市/地域 + 摄影 + 周末/假期等scripts/generate_and_publish.py 传参:图片路径列表 + 标题 + 正文 + 话题 + mode(默认 draft)| 约束 | 原因 | 违反后果 |
|---|---|---|
| 标题 ≤20 字(含 emoji) | 小红书前端字数限制 | 发布按钮被禁用,submit 静默失败 |
| 标题核心关键词前置 | 小红书搜索/推荐机制 | 流量差,用户搜不到 |
| 正文 300-800 字 | 小红书普通图文最佳长度区间 | 太短被算法降权;太长读者跳出 |
| 正文 3-5 段 | 阅读节奏友好 | 单段大块劝退 |
| 正文主题 + 位置前置 | 读者一眼知道主题和位置 | 抽象开头导致跳出 / 无地名读者找不到图 |
| 话题 2-5 个精准 # | 精准标签机制 | 太多稀释,太少不显 |
| 图片 1-9 张 | 小红书发布页最多 9 张缩略图 | 第 10 张起被忽略 |
| 图片 ≤5MB / 张 | 小红书上传接口限制 | 上传失败 |
| 首图承担点击理由 | 信息流点击决策主要由首图驱动 | 流量差 |
| 推荐竖图 3:4 | 小红书信息流主版式 | 横图/方图被裁切,首图效果差 |
| 图片清晰无水印 | 平台去重机制 + 用户体验 | 限流 / 被降权 / 举报 |
| 默认 mode=draft | 用户希望登录后手动点发布 | 误发布不可逆 |
| 自动化原则:脚本先校验内容对象再进浏览器 | 失败早暴露,不污染发布链路 | 浪费一次扫码会话 |
# 开头(小红书识别需要)scripts/generate_and_publish.py 在调 publish_xhs.py 前会做客户端校验(标题 ≤20 字 / 图片数 ≤9 / 文件存在),校验失败立即返回 status=error 不进入浏览器src/content_validator.py 在 publisher 启动时再校验一次(mode 合法 / images 扩展名 / publish 模式 ≥1 张图 / title ≤80 / body ≤2000)src/audit.py 每次执行都会保留:
actions.jsonl — 行为日志result.json — 最终结果(含 status / error / error_type)content.normalized.json — 归一化后的内容screenshots/*.png — 关键步骤截图dom/*.html — DOM 快照try/except 捕获,写入 result.json 后退出,不污染登录态不适合:绕过验证码 / 滑块 / 人机验证;批量互动、点赞、评论;操作未授权账号。
src/)publisher.py(700+ 行):核心发布逻辑(XhsPublisher.run)— draft 模式会点「保存草稿」写入服务端草稿箱content_validator.py:内容校验(标题字数、图片存在性、模式合法)duplicate_guard.py:重复发布保护(默认 30 分钟间隔)login_state.py:登录缓存(默认 6 小时)browser_session.py:持久化 Chromium profile + Playwrighthuman_behavior.py:人类行为模拟(避免反爬)locator_utils.py:DOM 定位工具audit.py:审计日志(每个 run 写 actions.jsonl)cloud_notify.py:飞书通知(login_qr.payload.json)src/publisher.py::XhsPublisher.save_draft_and_wait(状态:draft_persisted / draft_clicked_unconfirmed / draft_save_failed)/publish/publishconfig/selectors.json::save_draft_button_any(仅匹配保存草稿,绝不误触发「发布」按钮)系统级(整台机器,影响 OpenClaw service):
python3 / python3-venv / python3-pipxvfb(虚拟显示)MemoryMax ≥ 2.4G(绕开 Xvfb+Chromium cgroup OOM,2026-08-03 踩过坑)项目级(skill 目录内):
.venv + Python 依赖 + Playwright Chromiumruntime/{browser-profile,runs,lobster-notify,inbound}/runtime/lobster-notify/<run_id>/login_qr.payload.jsonXHS_PUBLIC_RUNTIME_BASE_URL)每次执行在 runtime/runs/<timestamp>/ 写入:
actions.jsonl — 行为日志result.json — 最终结果content.normalized.json — 归一化后的内容screenshots/*.png — 关键步骤截图dom/*.html — DOM 快照MODE=draft|publish(agent 通过命令行覆盖)LOGIN_TIMEOUT=300(默认 5 分钟扫码超时)PYTHON_BIN(默认 ${PROJECT_ROOT}/.venv/bin/python,可被覆盖)⚠️
.env文件当前只含MODE和LOGIN_TIMEOUT,不存 cookie / session token。但保留.env在 skill 目录外以避免误提交到 git。
agent (LLM)
↓ python3 scripts/generate_and_publish.py --image … --title … --body … --topic … --mode draft
scripts/generate_and_publish.py
├─ stage_images() → runtime/inbound/<prefix>_<NN>.<ext>
├─ write_content_json() → runtime/my_content.json
└─ subprocess.run([deploy/run_with_xvfb.sh, runtime/my_content.json], env={MODE: …})
↓
deploy/run_with_xvfb.sh
├─ 推导 PROJECT_ROOT = $(dirname ${BASH_SOURCE[0]})/..
├─ source .env(如存在)
└─ exec xvfb-run --auto-servernum --server-num=99 \
--server-args="-screen 0 1440x1000x24" \
.venv/bin/python scripts/publish_xhs.py \
--content runtime/my_content.json \
--mode ${MODE} \
--login-timeout ${LOGIN_TIMEOUT}
↓
scripts/publish_xhs.py (publisher CLI)
├─ load app.json + selectors.json
├─ ContentValidator + DuplicateGuard + LoginState
├─ BrowserSession(profile_dir=runtime/browser-profile)
└─ XhsPublisher.run(content)
├─ 登录检测 / QR payload 生成 / 飞书接管
├─ 上传图片 / 填正文
├─ mode==draft: 点「保存草稿」+ toast/URL 验证 → status=draft_persisted
├─ mode==publish: 点「发布」+ 等 published=true → status=published
└─ audit.write_json('result.json', result)
| 坑 | 症状 | 已修位置 |
|---|---|---|
| verify_filled body[:20] 跨换行 | innerText.includes 永远 false | src/publisher.py verify_filled(用 first_line[:20]) |
| body_input_any 误选评论框 | 填到 comment 而非 note body | config/selectors.json(placeholder 精确匹配 + [contenteditable]:not([class*='comment'])) |
| cgroup OOM | OpenClaw service 被 systemd 杀掉连带 exec session | systemd override MemoryMax=2.4G |
| cloud_notify._notify_dir base.name 丢父目录 | 嵌套配置路径错位 | 改用 run_dir.parent.parent.parent / configured(2026-08-04) |
| draft 模式只填表单不存 | 浏览器关后内容丢失,手机草稿箱看不到 | src/publisher.py::save_draft_and_wait(点「保存草稿」按钮 + toast/URL 信号验证);selectors save_draft_button_any 2026-08-04 新增 |
.env / runtime/runs/ / runtime/browser-profile/ 提交到 git用户输入:
[图1: 林荫步道,远山]
[图2: 狗尾草丛,夕阳]
[图3: 远山日落,树叶剪影]
"发小红书"
Agent 执行:
🌇 湖绿道|夕阳和夏天的尾巴 (17 字)["#湖绿道", "#散步", "#夏日氛围感", "#日落"](4 个,去掉"周末""城市漫游""拍照"3 个泛词)python3 ~/.openclaw/workspace/skills/xhs-content-creator/scripts/generate_and_publish.py \
--image <3 张图绝对路径> \
--title "🌇 湖绿道|夕阳和夏天的尾巴" \
--body "绕了半个城市,就为追这场日落。\n…" \
--topic "#湖绿道" --topic "#散步" \
--topic "#夏日氛围感" --topic "#日落" \
--mode draft
{"status":"ok","mode":"draft","publisher_status":"draft_persisted","publisher_run_id":"20260804-XXX",…}(draft_persisted 表示已落到服务端草稿箱,手机 app 可在草稿 tab 看到)