1. 为什么我要让 AI 替我点「发布」按钮
写博客这件事,最消耗耐心的从来不是写,而是发。Markdown 在本地编辑器里排版得好好的,粘进 CSDN 编辑器就可能出现代码块缩进错乱、标题层级被吞、图片要重新上传。一篇文章从写完到真正点下发布,中间往往要折腾十几分钟,纯体力活。
我想要的流程其实很简单:文章在本地写完,跟 AI 助手说一句「发到 CSDN」,剩下的交给它。这个想法落地需要三个东西配合——一个能操作浏览器的执行器、一个能理解自然语言指令的 Agent、以及一套稳定的发布技能包。csdn-publisher 就是这套链路里的「技能包」角色,它把「打开 CSDN 编辑器、填标题、灌正文、打标签、点发布」这一串动作封装成 Agent 可以调用的能力。
它适合谁?适合已经在用 OpenClaw 这类 AI Agent 框架、手里有 Markdown 写作习惯、并且不想每次手动搬运内容的人。如果你只是偶尔发一篇,手动复制粘贴其实也够用;但如果你每周要发好几篇,或者想让 Agent 在写完文章后顺手发布,那这套自动化就值得折腾一次。
整条链路的技术底座是 CDP(Chrome DevTools Protocol)。简单类比:CDP 就像是给 Chrome 浏览器开了一个「遥控接口」,外部程序可以通过它指挥浏览器打开页面、点击元素、输入文本。csdn-publisher 正是通过 CDP 连接到 Chrome,把 Markdown 内容注入到 CSDN 的编辑器里,而不是走传统的复制粘贴。这样做的好处是绕开了编辑器对剪贴板的格式解析,内容更稳定。
下面我会把整条链路拆开:先讲清楚 Agent 侧需要准备什么,再给出可复制的配置片段,然后跑一次从草稿到发布成功的完整验证,最后把我在过程中撞到的报错逐个列出来。你照着做,基本能一次跑通。
2. OpenClaw Agent 与 csdn-publisher 的前置准备
在动手之前,先把「谁负责什么」理清楚,不然后面排查问题会没有方向。
OpenClaw 是 Agent 的运行框架,它负责接收你的自然语言指令、决定调用哪个技能、把技能的执行结果反馈给你。csdn-publisher 是挂在它下面的一个技能(skill),专门负责 CSDN 发布这件事。Chrome 是被操作的目标,CDP 是它们之间的通信协议。三者关系可以这样理解:你说话给 OpenClaw,OpenClaw 调用 csdn-publisher,csdn-publisher 通过 CDP 指挥 Chrome 去操作 CSDN 页面。
2.1 环境依赖清单
先把需要的东西列全,缺一个后面都会卡住:
| 组件 | 作用 | 版本/形态要求 |
|---|---|---|
| OpenClaw | Agent 运行框架 | 已能正常启动并加载技能 |
| csdn-publisher | 发布技能包 | 放入 skills 目录 |
| Chrome / Chromium | 被 CDP 控制的浏览器 | 建议较新稳定版 |
| Node.js | 运行技能脚本 | 建议 18 LTS 及以上 |
| CSDN App | 扫码登录 | 手机端,用于首次授权 |
这里有个容易被忽略的点:Chrome 必须以「开启远程调试端口」的方式启动,CDP 才能连上它。普通双击打开的 Chrome 是没有开这个端口的,技能会连不上,报出类似connect ECONNREFUSED 127.0.0.1:9222的错误。所以启动 Chrome 时要带上--remote-debugging-port参数。
2.2 启动带调试端口的 Chrome
在服务器或本地机器上,用命令行启动 Chrome,指定调试端口和一个独立的用户数据目录。独立目录很重要,否则会和你日常用的 Chrome 配置冲突,甚至因为已有实例占用而无法开启调试端口。
# Linux / macOS 示例 chrome \ --remote-debugging-port=9222 \ --user-data-dir=/tmp/csdn-chrome-profile \ --no-first-run \ --no-default-browser-check# Windows PowerShell 示例 & "C:\Program Files\Google\Chrome\Application\chrome.exe" ` --remote-debugging-port=9222 ` --user-data-dir="C:\temp\csdn-chrome-profile" ` --no-first-run ` --no-default-browser-check启动后,浏览器地址栏访问http://127.0.0.1:9222/json/version,如果返回一段包含webSocketDebuggerUrl的 JSON,说明调试端口已经就绪。这一步是整个链路的地基,务必先确认它通了再往下走。
如果你的机器没有图形界面(纯服务器环境),需要在技能配置里开启 headless 模式,让 Chrome 无头运行。无头模式下扫码登录会稍微麻烦一点,因为你看不到浏览器窗口,但 csdn-publisher 会把登录二维码单独截出来发给你,所以依然可用。
2.3 把技能放进 skills 目录
csdn-publisher 的安装本质就是「放到正确的位置」。找到你的 OpenClaw 工作目录下的skills文件夹,把 csdn-publisher 整个目录拷贝进去。目录结构大致如下:
openclaw/ ├── skills/ │ └── csdn-publisher/ │ ├── skill.json │ ├── index.js │ └── config.example.json ├── config/ └── ...放好之后重启 OpenClaw,让它重新扫描技能目录。重启后你可以让 Agent 列出当前可用技能,确认 csdn-publisher 已经被识别。如果没识别到,八成是目录层级放错了,或者skill.json缺失。
2.4 关于模型与 API 接入
Agent 要理解你的指令、生成发布参数,背后需要一个大模型来驱动。如果你还没配好模型接入,可以先把这块打通。我用的是 TaoToken 的接入方式,Base URL 填https://taotoken.net/api,Key 在控制台生成,模型 ID 按你实际使用的填。这三件套(Base URL + Key + Model ID)是任何 OpenAI 兼容接入的通用配置,配好之后 Agent 才有「大脑」去调度 csdn-publisher。
具体来说,你需要在 OpenClaw 的模型配置里填入这三项。不同框架的配置文件位置不一样,但字段名基本一致。配完之后建议先用一次简单的对话测试,确认模型能正常返回,再去跑发布流程,这样出问题时能快速定位是模型层还是技能层的问题。
3. 可复制的 csdn-publisher 配置与 CDP 连接参数
这一节是全文的核心,所有片段都可以直接复制改路径使用。配置分两块:一块是 csdn-publisher 自己的技能配置,一块是 OpenClaw 调用它时的 Agent 触发配置。
3.1 csdn-publisher 技能配置
在技能目录下,把config.example.json复制成config.json,然后按下面的结构填写。注意路径要换成你自己的实际路径。
{ "browser": { "cdpEndpoint": "http://127.0.0.1:9222", "headless": false, "userDataDir": "/tmp/csdn-chrome-profile", "launchArgs": [ "--no-first-run", "--no-default-browser-check", "--disable-blink-features=AutomationControlled" ] }, "csdn": { "editorUrl": "https://editor.csdn.net/md/", "publishTimeoutMs": 60000, "defaultTags": ["AI", "自动化"], "category": "人工智能" }, "login": { "method": "qrcode", "cookieStore": "./.cache/csdn-cookies.json", "notifyChannel": "feishu" }, "model": { "baseUrl": "https://taotoken.net/api", "apiKey": "sk-你的Key", "modelId": "你的模型ID" } }几个关键字段说明一下。cdpEndpoint必须和你启动 Chrome 时的调试端口一致,默认 9222。headless在服务器上设为 true,本地调试建议 false,方便你肉眼观察浏览器动作。cookieStore是登录态持久化的位置,扫码成功后 Cookie 会写到这里,下次就不用再扫。notifyChannel决定二维码发到哪个聊天软件,支持飞书、Telegram 等。
注意:
apiKey不要直接明文提交到 Git 仓库。生产环境建议用环境变量注入,配置里写${TAOTOKEN_API_KEY}这种占位符,由框架在运行时替换。
3.2 OpenClaw Agent 触发配置
技能配好后,还要让 Agent 知道「什么指令该调用 csdn-publisher」。这通常在 OpenClaw 的 Agent 配置里声明。下面是一个 TOML 形式的示例,字段名按你实际框架调整。
[[agents.skills]] name = "csdn-publisher" enabled = true trigger_keywords = ["发博客", "发布到CSDN", "发文章"] entry = "skills/csdn-publisher/index.js" timeout_ms = 120000 [agents.skills.params] auto_fill_title = true auto_fill_tags = true confirm_before_publish = truetrigger_keywords是自然语言触发的关键词,你说「帮我发博客」时 Agent 就会匹配到这个技能。confirm_before_publish建议设为 true,这样 Agent 在真正点发布前会先跟你确认一次,避免误发。等你用熟了再考虑关掉。
3.3 CDP 连接参数详解
CDP 连接是整条链路最容易出问题的地方,单独展开讲。csdn-publisher 连接 Chrome 有两种方式:一种是连到已经开好调试端口的 Chrome(推荐),另一种是让技能自己拉起一个 Chrome 实例。
连已有实例时,cdpEndpoint指向http://127.0.0.1:9222,技能会去请求/json/version拿到 WebSocket 地址,再建立连接。这种方式的好处是登录态可以复用,你手动登录一次,技能就能一直用。
让技能自己拉起 Chrome 时,launchArgs里的参数就很重要。--disable-blink-features=AutomationControlled是为了降低被识别为自动化脚本的概率,某些站点对navigator.webdriver有检测,这个参数能缓解。--user-data-dir指定独立配置目录,保证登录态隔离且可持久化。
如果你在容器里跑,还要注意 Chrome 的沙箱问题。容器内通常需要加--no-sandbox,否则 Chrome 起不来。但这个参数有安全代价,仅建议在隔离良好的容器环境使用。
{ "browser": { "cdpEndpoint": "http://127.0.0.1:9222", "headless": true, "launchArgs": [ "--no-sandbox", "--disable-dev-shm-usage", "--disable-gpu" ] } }--disable-dev-shm-usage解决容器内/dev/shm太小导致 Chrome 崩溃的问题,--disable-gpu在无显卡环境避免 GPU 相关报错。这三个参数是容器化部署的常见组合,先加上能省不少排查时间。
3.4 登录态与 Cookie 持久化
首次运行会触发扫码登录。Agent 检测到未登录时,会通过 CDP 截取登录二维码,然后按notifyChannel发到你的聊天软件。你扫码确认后,技能把 Cookie 写入cookieStore指定的文件。
这里有个细节:Cookie 文件要保证读写权限,且不要放在会被清理的临时目录。我一开始放在/tmp下,机器重启后登录态就没了,又得重扫。后来改到项目目录下的.cache里,稳定多了。另外 Cookie 有有效期,CSDN 的登录态一般能维持较长时间,但如果长时间不用,还是可能失效,届时重新扫码即可。
4. 从草稿到发布成功的完整验证
配置都就位后,跑一次端到端验证。这一步的目的是确认「Agent 能触发技能、技能能连上 Chrome、Chrome 能操作 CSDN、内容能成功发布」这四件事全部打通。
4.1 准备一篇测试草稿
先写一篇最简单的 Markdown 作为测试,别用带复杂图片和表格的文章,减少变量。比如:
# 测试文章标题 这是一篇用于验证 csdn-publisher 链路的测试文章。 ## 小标题 - 列表项一 - 列表项二 ```python print("hello csdn")把这篇草稿保存为 `test-post.md`,放在 Agent 能访问到的路径下。 ### 4.2 触发 Agent 发布 在 OpenClaw 的对话界面里,输入类似这样的指令: ```text 把 test-post.md 发布到 CSDN,标题用「csdn-publisher 链路验证」,标签加上 自动化Agent 收到指令后,会匹配到 csdn-publisher 技能,然后按顺序执行:连接 CDP、检查登录态、打开 CSDN 编辑器、填入标题和正文、设置标签、等待你确认、点击发布。
如果你开了confirm_before_publish,这一步 Agent 会先把即将发布的内容摘要发给你,你回复确认后它才真正点发布。这个设计很有必要,我第一次测试时标题填错了,幸好有确认环节拦住了。
4.3 观察执行日志
执行过程中,技能会输出日志。重点看这几个检查点:
[csdn-publisher] CDP connected: ws://127.0.0.1:9222/devtools/page/XXXX [csdn-publisher] login state: valid (cookie loaded) [csdn-publisher] editor opened: https://editor.csdn.net/md/ [csdn-publisher] title filled: csdn-publisher 链路验证 [csdn-publisher] content injected: 412 chars [csdn-publisher] tags set: ["自动化"] [csdn-publisher] waiting for confirm... [csdn-publisher] publish clicked [csdn-publisher] publish result: success, articleId=123456789看到CDP connected说明浏览器连接成功;login state: valid说明登录态有效;content injected说明正文注入成功;最后publish result: success就是发布成功了。如果中间某一步卡住,日志会停在那一行,对照下一节的排查表定位。
4.4 验证发布结果
发布成功后,去 CSDN 的「内容管理」里看这篇文章是否出现。注意 CSDN 有审核机制,刚发布时状态可能是「审核中」,这不代表失败。等几分钟刷新,状态变成「已发布」就彻底完成了。
我实测下来,从触发指令到看到发布成功日志,整个过程大约 20 到 40 秒,取决于网络和 CSDN 页面加载速度。相比手动复制粘贴再排版,效率提升还是很明显的,尤其是批量发布的时候。
5. 常见报错与排查对照表
这一节把我踩过的坑和对应的解法列出来,你遇到报错时可以直接对照。
5.1 连接类报错
报错:connect ECONNREFUSED 127.0.0.1:9222
这是最常见的错误,意思是技能连不上 Chrome 的调试端口。原因通常是 Chrome 没有以调试模式启动,或者端口被占用。排查步骤:先在浏览器访问http://127.0.0.1:9222/json/version,如果打不开,说明 Chrome 没开调试端口,按 2.2 节重新启动。如果端口被别的程序占用,换个端口,比如 9223,同时改配置里的cdpEndpoint。
报错:local proxy failed或连接超时
这类报错通常和网络环境有关。检查你的机器能否正常访问 CSDN 页面,以及 CDP 端点是否被防火墙拦截。如果是容器环境,确认端口映射是否正确,9222有没有从容器映射到宿主机。
5.2 登录类报错
报错:401 Unauthorized或login state: invalid
说明登录态失效了。可能是 Cookie 过期,也可能是 Cookie 文件被清理。解法是重新触发一次扫码登录,让 Agent 重新发二维码给你。如果频繁失效,检查cookieStore路径是否可写、是否被其他进程清理。
报错:OAuth callback timeout
如果你用的是 OAuth 类登录方式,回调超时通常是网络问题或回调地址配置不对。改用扫码登录(method: qrcode)能绕开这类问题,CSDN 的扫码登录更稳定。
5.3 内容注入类报错
报错:reading 'choices' of undefined
这个报错一般出现在模型调用环节,说明模型返回的结构不符合预期。检查model配置里的baseUrl、apiKey、modelId三件套是否填对。Base URL 应该是https://taotoken.net/api,Key 要和控制台生成的一致,Model ID 要和你实际开通的模型匹配。三者任一填错都会导致返回结构异常。
报错:正文注入成功但格式错乱
如果代码块或表格在 CSDN 里显示不正常,检查你的 Markdown 是否符合 CommonMark 规范。csdn-publisher 走的是 CDP 注入,对 Markdown 语法的容错比手动粘贴低,建议用标准语法。另外,本地图片需要先转成在线链接,技能目前主要处理纯文本 Markdown。
5.4 发布类报错
报错:publish button not found
CSDN 编辑器页面结构可能更新了,导致技能找不到发布按钮。这种情况需要更新 csdn-publisher 到最新版本,或者检查editorUrl是否还是有效的编辑器地址。CSDN 偶尔会调整编辑器路径,配置里的 URL 要跟着更新。
发布成功但文章不显示
前面提过,CSDN 有审核流程。发布成功日志只代表内容提交成功,不代表已经对外可见。去内容管理看状态,审核中属于正常,等审核通过即可。如果长时间卡在审核中,检查文章是否触发了某些敏感词规则。
5.5 排查通用思路
遇到任何报错,先按「模型层 → 技能层 → 浏览器层 → 目标站点层」的顺序排查。模型层看三件套配置,技能层看日志停在哪一步,浏览器层看 CDP 端口通不通,目标站点层看 CSDN 页面是否正常。这个顺序能帮你快速缩小范围,避免在错误的方向上浪费时间。
6. 把发布这件事交给 Agent 之后
跑通之后,我的写作流程变成了这样:在本地用 Markdown 写完,检查一遍,然后跟 Agent 说一句「发到 CSDN,标签加上 XX」。剩下的它自己搞定,我只需要在确认环节点个头。省下来的时间,够我多写半篇文章。
如果你想让 Agent 在发布之外还能帮你做更多事,比如根据草稿自动生成摘要、自动配标签、甚至根据历史文章风格润色,那模型接入这块就值得多花点心思。TaoToken 的模型对话能力可以在这里派上用场,你可以直接开一个对话测试不同模型对文章润色的效果,找到最适合你写作风格的那个。
对于长期要跑自动化发布、甚至想让 Agent 参与内容生成和排版的场景,可以考虑用 Coding Plan 这类方案,把模型调用和技能调度统一管理起来,省得每次单独配。接入文档里有完整的配置说明,照着填三件套就能跑。
发布这件事本身不复杂,复杂的是让它稳定、可复用、不折腾。把链路搭好之后,你就能真正把精力放回内容本身,而不是消耗在点击和排版上。