OpenCLI 小红书图文发布实战:publish workflow 从命令到 shadow DOM 自动化的完整解析 OpenCLI 小红书图文发布实战publish workflow 从命令到 shadow DOM 自动化的完整解析【免费下载链接】OpenCLIMake Any Website into CLI Use your logged-in browser by AI agent.项目地址: https://gitcode.com/gh_mirrors/ope/OpenCLI导读本文基于 OpenCLI 仓库中sitemaps/xiaohongshu/workflows/publish.md这一站点工作流文档系统讲解如何让 AI Agent 借助opencli xiaohongshu publish命令在已登录的浏览器中自动发布小红书图文笔记标题 正文 1-9 张本地图片 可选话题。你将掌握publish 命令的完整参数与执行前提、最佳路径与降级路径Fallback的切换逻辑、creator center 独立域与 closed shadow DOM 发布按钮两大核心难点、中断恢复检查点Re-entry checkpoints与发布结果验证方法以及文档中逐条列出的安全红线与失效标记Stale markers。文末还会深入clis/xiaohongshu/publish.js源码与测试用例说明每条动作背后的实现原理。背景publish workflow 在整个小红书 sitemap 中的位置在 OpenCLI 的站点文档体系中sitemaps/xiaohongshu/SITE.md将小红书xiaohongshu.com定义为图文笔记 短视频 social feed并明确指出 Agent 的主要任务是搜笔记 / 发笔记 / 读笔记内容 评论 / 看 creator 数据。围绕这些目标仓库提供了三类工作流文档搜索笔记发布图文笔记本文主题workflows/publish.md评论笔记同时发布流程依赖两个关键页面/坑位文档发布表单页面 compose.md描述 creator center 发布表单的视觉锚点Visual anchors与 5 个 action上传图片、填文字、加话题、提交发布、存草稿站点级坑位 pitfalls.md汇总 task-executing agent 执行工作流时会撞的坑其中creator_center_is_different_host、publish_button_shadow_dom、title_input_has_hidden_decoy、security_block_on_repeated_access与发布直接相关。本文聚焦 publish workflow 本身其余站点能力feed / search / note detail仅作为验证环节的背景提及不展开。发布目标Goal与范围边界publish workflow 的目标非常明确发一篇图文笔记标题≤20 字 正文 1-9 张本地图片可选 topic 话题。文档同时划定了v1 PoC 的明确边界以下能力不在本次范围视频笔记 / 长文 / 私密 / 定时发布 / 用户 / 位置 均不支持草稿保存不等于发布成功草稿走同一页面上的save_draftaction通过--draftflag 触发不算 workflow 完成。状态签名State signature工作流文档用状态签名描述进入与成功的判定条件entry入口任意页面logged_in本地图片路径 ready标题 / 正文 string readysuccess成功opencli xiaohongshu creator-notes列表里出现新笔记title 匹配或 publish toast发布成功。这条签名在源码中被实现为发布后的双重校验见 publish.js 的 Step 8页面出现成功标记文案发布模式匹配发布成功/上传成功草稿模式匹配草稿已保存/暂存成功/保存成功/保存于/图文笔记(或当前 URL 已离开/publish/publishnavigatedAway。两者任一成立即判定成功随后返回status: ✅ 发布成功。最佳路径Best path一条命令直发前置条件adapter: opencli xiaohongshu publish adapter_health: healthy preconditions: - logged_in (creator.xiaohongshu.com 同 cookie 共享) - title 20 chars - 1-9 local image paths (jpg/png/webp, 10MB each) - body text ready estimated_turns: 1命令格式与完整参数opencli xiaohongshu publish --title title body \ --images /path/a.jpg,/path/b.jpg \ [--topics 生活,旅行]结合 publish.js 的 args 定义完整参数表如下参数类型必填说明contentpositional是笔记正文string--titlestring是笔记标题最多 20 字--imagesstring否图片路径逗号分隔最多 9 张支持 jpg/png/gif/webp--card-textstring否文字配图卡片文字多张卡片用\|\|\|分隔卡内换行用\n--card-stylestring否文字配图卡片样式运行时按页面实际选项匹配找不到会失败省略时使用基础--topicsstring否话题标签逗号分隔不含#号--draftbool否保存为草稿不直接发布默认 falseadapter 内部执行navigate creator host → CDP file upload → shadow DOM submit见 publish.js 头注释 的 5 步流程。参数校验细节源码级adapter 在导航前会做快速失败fast-fail校验见 publish.js--title缺失 →ArgumentError标题超过 20 字符MAX_TITLE_LEN 20→ArgumentErrorpositionalcontent缺失 →ArgumentError--images与--card-text都没给 →ArgumentError图片数量超过MAX_IMAGES 9→ArgumentError文字配图模式下追加的图片不支持.gif编辑器图片入口只接受 jpg/jpeg/png/webp→ArgumentError图片路径不存在或扩展名不在SUPPORTED_EXTENSIONS { .jpg, .jpeg, .png, .gif, .webp }内 →ArgumentErrorvalidateImagePaths 在导航前就把坏路径挡掉避免白跑一趟页面。登录态与 creator 域校验执行中 adapter 会先page.goto(PUBLISH_URL)即https://creator.xiaohongshu.com/publish/publish?frommenu_lefttargetimage随后检查location.href是否仍包含creator.xiaohongshu.com若被重定向走session 过期会抛出错误提示重新捕获登录Redirected away from creator center — session may have expired. Re-capture browser login via:opencli xiaohongshu creator-profile这条防线来自 pitfalls 中的creator_center_is_different_hostcreator center 与主站是两套 DOM虽然共享 SSO同一web_sessioncookie但发布入口只存在于creator.xiaohongshu.com。降级路径Fallback pathadapter 失败后的手操流程当 adapter 抛出 typed errorAuthRequiredError/CommandExecutionError或卡死超过 60s 时Agent 切换至 Fallback pathon_adapter_fail: - adapter_health_update: opencli xiaohongshu publish - suspect - if AuthRequiredError: - recovery: opencli xiaohongshu login # pending: codex task #276 - 登录后 retry adapter 一次 - opencli browser state (verify host URL) - if host ! creator.xiaohongshu.com: goto https://creator.xiaohongshu.com/publish/publish?frommenu_lefttargetimage - action:upload_images in pages/compose.md (CDP DOM.setFileInputFiles) - wait 3s for upload settle - action:fill_text in pages/compose.md (title visible filter body contenteditable) - 如果 topics 非空: action:add_topics in pages/compose.md - action:submit_publish in pages/compose.md - **注意**: publish button 是 closed shadow DOM, host-level click 不响应 - 必须 evaluate 实例方法 _onPublish / onPublish / _onSubmit / _handlePublish - verify URL redirect 到 /creator/notes 或 toast 发布成功 - cross-verify: opencli xiaohongshu creator-notes --limit 1 看顶部是否是新发的 estimated_turns: 8关于 login 命令的现状workflow 文档标注opencli xiaohongshu login为 pendingcodex task #276。从当前仓库看登录命令已经由 site-auth.js 中的registerSiteAuthCommands统一注册opencli xiaohongshu whoami读取命令探测当前登录账号auth.js 通过访问creator.xiaohongshu.com/new/home并 fetch/api/galaxy/creator/home/personal_info验证身份返回 username followers未登录抛AuthRequiredErroropencli xiaohongshu login写命令先探测是否已登录already_logged_in否则打开登录页并轮询等待人工完成登录默认超时 300 秒成功返回login_completequickCheck只检查web_sessioncookie 是否存在weak 预检见 SITE.md 的 cookie_probe。Fallback 中的四个关键动作对应 compose.mdFallback 手操流程逐条对应 compose.md 的 Actionsupload_images通过 CDPDOM.setFileInputFiles设置文件输入图片预览区 3s 内出现缩略图视为 settle失败时检查图片格式jpg/png/webp 10MB、最多 9 张MAX_IMAGESadapter 内置 base64 fallbackfill_text向标题输入框visible filter输入标题 向正文 contenteditable 输入正文标题超过 20 字 / 正文超过 1000 字需要截断add_topics话题非空时触发#话题联想并点击选项话题添加失败可跳过非必需但 persistent fail 要把 adapter_health 标 suspectsubmit_publish必须调用 shadow DOM 实例方法见下节成功后 redirect 到/creator/notes或出现发布成功toast。核心难点一closed shadow DOM 发布按钮这是整个发布流程最容易踩的坑。creator center 的发布/保存按钮被封装在xhs-publish-btn自定义元素中背后是 closed shadow rootpublish.js 注释Host-level.click()无法 dispatch 进内部 handler。因此 adapter 使用实例方法调用instance method invocation依次尝试发布[_onPublish, onPublish, _onSubmit, _handlePublish]PUBLISH_METHOD_NAMES存草稿[_onSave, _onSaveDraft, _onDraft]DRAFT_METHOD_NAMES。发布提交逻辑 分两路Path 1主路遍历页面上所有可见的xhs-publish-btnhost 元素 × 全部候选方法名逐个host[name]()调用即使某个方法抛错也不立刻放弃多个 host 可能并存后面的方法名可能成功最终返回{ ok: true, via: method, name }Path 2兜底若方法调用全部 miss退化为按可见文本匹配button/[rolebutton]并.click()匹配发布/发布笔记或草稿模式的暂存离开/存草稿。草稿模式还有第三层兜底点击返回/关闭/取消/离开触发离开并暂存流程再点击暂存离开/存草稿/保存草稿甚至检测页面是否已自动保存出现草稿箱(/保存于/编辑于标记。对应的测试用例见 publish.test.jsuses the shadow-DOM method-invoke path when xhs-publish-btn handler succeeds。pitfalls.md 中publish_button_shadow_dom明确警告不要手 click如果 adapter broken 必须手动用opencli browser evaluate调实例方法而不是 click。核心难点二标题输入框的 hidden decoy可见性过滤creator center 的标题输入框存在两套同 class 的实现一对 4px 宽的隐藏 scaffolding input空 placeholdersubmit 时 v-model 不 commit加上真正可见的输入框pitfall:title_input_has_hidden_decoy。若用 page-level selector 或nth-child直接选输入会丢进隐藏框标题永远为空。解法分两层adapter 层TITLE_SELECTORS按优先级排列publish.jsplaceholder 类 selector含标题或title优先于 class 类 selector从根源上避开隐藏 decoyfallback 层按 placeholder 文本请输入标题加 visible filteroffsetWidth 50选可见输入框不要按 nth-child / first matchcompose.md Visual anchors。fillField 的实现 进一步做了三阶段保护locate跳过offsetParent null的隐藏元素→ apply用原生 setter beforeinput/input/change事件序列模拟真实输入contenteditable 走document.execCommand(insertText)或page.insertText→ verify输入后校验el.value/innerText与期望值一致不一致则截图到/tmp/xhs_publish_field_debug.png并抛错。测试用例aborts when the title does not stick after filling与falls back to in-page insertion when contenteditable native insertText fails正是覆盖这两条路径。核心难点三话题的内联 # 流添加方式旧版 creator center 有独立的添加话题按钮 搜索输入框新版编辑器已移除该入口。现在必须走编辑器原生的内联流程addTopics 实现focus 正文 contenteditable 并把光标移到末尾用 CDP 原生page.insertText输入#话题不能用execCommand否则 XHS 不触发 keyup 监听、联想下拉不弹出等待 1.2s 让联想下拉渲染下拉位于 closed shadow root 内light-DOM 无法枚举但 XHS 会自动高亮第一个匹配项所以直接pressKey(Enter)接受校验话题实体真实生成通过正文 innerText 中的稳定标记#话题[话题]数量是否增加来判断topicMarkerCountScript。这里有个重要的写侧后置条件write-side postcondition如果请求的话题最终没有生成真实话题实体只有裸#textadapter在发布前就失败而不是静默发出带裸#的笔记。测试attaches topics via Enter to accept the inline suggestion (shadow-DOM dropdown)、fails typed when XHS does not render the topic chip marker after Enter、does not accept a pre-existing topic marker as proof of a new attached topic三个用例完整覆盖了这一行为。文字配图--card-text / --card-style扩展能力虽然 v1 workflow 文档聚焦标题 正文 本地图片publish adapter 还实现了完整的文字配图子流程runTextImageFlow点击文字配图入口 → 等待 tiptap/ProseMirror 卡片编辑器出现.tiptap.ProseMirrorselector逐卡输入文字多卡用\|\|\|分隔卡内换行用\n每行通过pressKey(Enter)产生真实换行shell 单引号传入的\n字面量会被归一化为真实换行点击生成图片等待进入预览图片步骤生成图片在卡片文字注册进编辑器模型前会 no-op因此带重试且点击后按钮消失保证不会重复添加可选--card-style样式条.cover-list-container是虚拟化列表一次只渲染视口附近的 ~10/20 个选项因此selectCardStyle逐步滚动累加所有标签目标样式出现后scrollIntoView再点击样式是内容相关的动态子集没有静态白名单CARD_STYLE_GUIDE仅供--help展示点击下一步回到标准编辑器之后照常填标题 / 正文 / 话题 / 提交。CARD_STYLE_GUIDE中预置了 21 种样式及适用场景基础/边框/备忘/清新/涂写/便签/光影/涂鸦/简约/手写/插图/美漫/弥散/柔和/印刷/科技/贺卡/札记/书摘/手帐/几何。测试覆盖单卡、多卡、\n换行、字面量\n等场景publish.test.js。Avoid禁止清单与安全红线workflow 文档明确列出 6 条 Avoid均可在 pitfalls.md 中找到对应依据不要在www.xiaohongshu.com找发布入口—pitfall:creator_center_is_different_host主站顶 nav 的发布只是跳到 creator host手 click 容易撞 popup / iframe / sso refresh 链不要 host-level.click()xhs-publish-btn—pitfall:publish_button_shadow_dom看似点击成功但表单不提交不要用 page-level selector 找 title input—pitfall:title_input_has_hidden_decoy必须加 visible filteroffsetWidth 50安全验证 modalCAPTCHA / 滑块 / 短信 2FA弹出即停手报 user不要尝试自动解 — 这是 human-only 红线publish 失败后不要立刻 retry 5 次—pitfall:security_block_on_repeated_access短时间高频访问/重试会触发安全限制/访问链接异常URL 含website-login/error或error_code300017|300031触发后 60s 内不重试同 URLworkflow 内用 1-2s wait 隔开连续请求不要把--draft当 fallback— 草稿 ! 已发布不算 workflow 成功。中断恢复检查点Re-entry checkpointsAgent 被中断后醒来应按opencli browser state的 URL creator-notes比对判断当前进度publish.md当前状态处理方式非 creator host重新走 Best path在/publish/publish?...图片已上传但 title/body 未填从 Fallback 的fill_text步继续已在/creator/notes或 toast发布成功已显示已完成用creator-notes交叉验证顶部安全验证 modal 可见停手报 user状态验证State validation与交叉验证workflow 的最终成功判定三选一即可publish.mdopencli xiaohongshu creator-notes --limit 5顶部出现 title 匹配的新行creator.xiaohongshu.com/creator/notesURL 上看到新笔记 cardvisible text 匹配publish toast发布成功出现过。creator-notes 的读取原理creator-notes.js 采用三级降级读取fetchCreatorNotesCapture 路径首选在 dashboard 根页安装window.__xhsCapture钩子同时 hookfetch与XMLHttpRequest只捕获/api/galaxy/签名接口因为从page.evaluate直接fetch()会绕过 x-s 签名导致 406随后通过history.pushStatepopstate触发 SPA 导航发出page_num1的签名请求再翻页收集全部note_infosAPI 路径直接 fetch/api/galaxy/creator/datacenter/note/analyze/list失败时用 interceptor 捕获DOM 兜底访问new/note-manager滚动解析div.note卡片新发布笔记在 analyze API 中title为空需从 note-manager 的 DOM 补标题。返回字段rank / id / title / date / views / likes / collects / comments / url其中 url 为creator.xiaohongshu.com/statistics/note-detail?noteId...。草稿的验证--draft保存成功后可用opencli xiaohongshu drafts列出本地草稿箱drafts.js支持--type image/video/article/audio默认 image成功标记见源码[草稿已保存, 暂存成功, 保存成功, 保存于, 图文笔记(]。失效标记Stale markers何时判定页面结构漂移workflow 文档给出三个页面结构漂移信号一旦命中应把 adapter_health 标为 suspectpublish.mdshadow DOM publish button 实例方法名变化_onPublishfamilyadapter 内部 fallback 链全 misstask agent 会在 Fallback step 卡住title input class 漂 / hidden decoy 结构换visible filter 阈值offsetWidth 50需要调整creator center URL 的from/targetquery 变化goto URL 需要更新。这些信号与 compose.md 的 Page pitfalls 一一对应是维护者判断页面又改版了的第一手依据。从文档到代码完整调用链一览将 workflow 文档与源码对照publish 的端到端调用链为opencli xiaohongshu publish→ publish.jscli()定义access: write、strategy: Strategy.COOKIE、browser: true、domain: creator.xiaohongshu.com参数校验title ≤ 20、images ≤ 9、格式校验→page.goto(PUBLISH_URL)并验证仍在 creator 域图文 tab 选择 → 上传CDPDOM.setFileInputFiles优先base64 DataTransfer 兜底500KB 的 base64 载荷会警告升级 extension v1.6→waitForUploads轮询上传进度条消失waitForEditForm等待编辑器渲染新版 UI 上传图片后才渲染编辑表单fillField填标题与正文三阶段locate/apply/verify→addTopics内联话题shadow DOM 实例方法提交 → 成功标记 URL 离开校验opencli xiaohongshu creator-notes --limit 1交叉验证新笔记出现在列表顶部。全套行为由 publish.test.js90 处与 publish 相关的断言守护覆盖 CDP 上传、DataTransfer 兜底、shadow-DOM 方法调用、hidden decoy 过滤、话题实体校验、参数快速失败、文字配图多卡等场景。小结workflows/publish.md是一份面向 AI Agent 的可执行工作流契约它以opencli xiaohongshu publish为单一入口把发图文笔记压缩成一条命令又以精确的 Fallback 步骤、Avoid 清单、Re-entry checkpoints 和 Stale markers把页面结构漂移、登录失效、安全风控等现实风险显式化。理解这份文档等于同时理解了 OpenCLI 的站点适配哲学——human authenticates, machine verifies以及面对 closed shadow DOM、hidden decoy、签名 API 等现代前端对抗手段时的工程化应对方式。对希望基于 OpenCLI 构建小红书内容自动化管线的开发者本文列出的命令参数、源码路径与测试用例即是可直接复用的起点。【免费下载链接】OpenCLIMake Any Website into CLI Use your logged-in browser by AI agent.项目地址: https://gitcode.com/gh_mirrors/ope/OpenCLI创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考