基于OpenClaw的番茄小说作者半自动化发布工具实践
浏览器自动化是提升Web操作效率的核心技术,其原理是通过脚本程序控制浏览器,模拟用户点击、输入等交互行为。这项技术的价值在于将人类从重复、机械的网页操作中解放出来,实现流程的标准化与批量化处理,尤其适用于内容发布、数据采集等场景。在内容创作领域,作者常面临平台后台操作繁琐、批量处理效率低下的痛点。本文介绍的半自动化发布工具,正是基于OpenClaw等浏览器自动化框架,构建了一套“流程自动化,决策人
1. 项目概述:一个为番茄小说作者设计的半自动化发布工具包
如果你是一名在番茄小说平台连载作品的作者,每天最繁琐的工作之一,可能就是打开后台,复制章节标题,粘贴正文,点击保存草稿,最后再手动发布。这个过程看似简单,但日复一日,尤其是在需要批量处理多章存稿时,就变成了纯粹的体力活,还容易因手滑而出错。 fanqie-author-publish 这个项目,正是为了解决这个痛点而生。它不是一个追求“全自动、无人值守”的激进方案,而是一个 “人机协作、稳字当头” 的半自动化技能包。它的核心目标不是取代作者,而是成为作者的高效助手,将你从重复的机械操作中解放出来,让你能更专注于内容创作本身。
这个工具包的设计哲学非常务实:它运行在 Linux 环境下,依托 OpenClaw 这类浏览器自动化框架,模拟你在番茄作者后台的一系列操作。但它把最关键的一步—— 最终发布 ——留给了人工确认。简单来说,它的工作流是:你准备好章节内容(标题和正文),工具帮你自动打开后台、填入内容、保存为草稿;然后, 由你亲自在浏览器里检查一遍 ,确认无误后,再通过一个简单的指令(或点击)完成发布。这种“机器执行,人类决策”的模式,在效率和安全之间取得了最佳平衡,特别适合对作品发布持谨慎态度的创作者。
2. 核心设计思路与方案选型
2.1 为什么选择“半自动”而非“全自动”?
在内容发布领域,尤其是涉及个人创作成果的平台,盲目追求全自动化是高风险行为。平台的风控策略、验证码的随机出现、页面结构的细微调整,都可能让一个脆弱的全自动脚本瞬间失效,甚至导致账号异常。 fanqie-author-publish 从一开始就规避了这些陷阱。
它的设计核心是 “流程自动化,决策人工化” 。自动化处理的是确定性强、重复性高的部分:导航到指定页面、定位输入框、填充文本、点击保存按钮。这些操作基于清晰的页面元素选择器,相对稳定。而将“发布”这个会产生实际影响、且可能触发平台风控的关键动作,交由人工确认。这不仅仅是出于安全考虑,更是对创作本身的尊重——最终让作品面世的,应该是作者本人的一次有意识的点击。
2.2 为什么基于 Linux 和 OpenClaw?
选择 Linux 作为目标运行环境,主要出于稳定性和可控性的考虑。Linux 服务器或桌面环境通常可以 7x24 小时稳定运行,适合安排定时任务(如凌晨自动保存草稿)。同时,其命令行环境使得脚本的部署、日志记录和故障排查更加清晰和标准化。
OpenClaw 在这里代表了一类现代的浏览器自动化控制框架(例如,你也可以理解为基于 Playwright 或 Puppeteer 封装的工作流引擎)。与传统的、基于图像识别的自动化工具相比,这类框架直接与浏览器引擎交互,通过 CSS 选择器或 XPath 精准定位页面元素,执行速度快,稳定性高,且能更好地处理复杂的单页面应用(SPA),就像番茄作者后台这类系统。项目自带的 playwright-fanqie-publish-example.js 文件,就是一个使用 Playwright 实现核心流程的绝佳范例,清晰地展示了如何与 ProseMirror 这类富文本编辑器进行交互。
2.3 输入与输出的结构化设计
工具包采用了高度结构化的 JSON 文件来定义输入,这体现了工程化思维。 chapter.template.json 和 chapters.batch.template.json 这两个模板文件,定义了工具需要知道的一切:作品名、章节标题、正文内容、要执行的动作、源文件路径以及备注信息。
这种设计的好处是多方面的:
- 可追溯 :
source_file字段记录了章节内容的来源,方便回溯和对照。 - 可批量 :批量模板允许一次性准备多个章节,极大地提升了准备效率。
- 可校验 :配套的
input.schema.json文件定义了数据格式的规范,可以在执行前进行有效性检查,避免因数据格式错误导致流程中断。 - 职责分离 :作者只需要关心内容(编辑好 Markdown 或文本文件),然后按照模板填写 JSON 即可,无需关心自动化脚本的内部逻辑。
3. 环境准备与初始化实操
3.1 Linux 环境基础配置
假设你已经在 Ubuntu 22.04 LTS 或同级别的 Linux 发行版上准备好了基础环境。首先,需要确保系统已安装必要的工具:
# 更新包列表并安装 Git 和 Node.js(如果使用 Playwright 示例脚本)
sudo apt update
sudo apt install -y git nodejs npm
# 建议安装较新版本的 Node.js,可通过 NodeSource 仓库
curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash -
sudo apt install -y nodejs
# 验证安装
node --version
npm --version
接下来,为项目创建一个独立的工作空间。遵循项目建议,避免使用 root 用户目录,而是为你的作者身份创建一个专属目录:
# 创建用户(如果尚未创建)
sudo adduser author
# 切换到该用户
su - author
# 创建项目根目录
mkdir -p ~/openclaw-skills
cd ~/openclaw-skills
3.2 获取与初始化技能包
将 fanqie-author-publish 项目克隆到本地:
git clone <项目仓库地址> fanqie-author-publish
cd fanqie-author-publish
现在,运行项目提供的初始化脚本 setup-linux.sh 。这个脚本的作用是完成基础检查,并创建必要的运行时目录。
# 赋予脚本执行权限
chmod +x setup-linux.sh
# 执行初始化,可以指定父目录,不指定则默认为当前目录
bash setup-linux.sh ~/openclaw-skills
执行后,脚本会:
- 检查
manifest.json、SKILL.md等核心文件是否存在。 - 创建
logs/和screenshots/目录,用于存放运行日志和过程截图。 - 输出后续的联调建议。 如果一切顺利,你会看到类似“初始化完成,请开始联调”的提示。 重要提示 :
logs/目录下的example-log.md是一个日志模板,强烈建议你在每次运行前复制它并重命名,用以记录当次操作的所有细节,这是事后排查问题的黄金依据。
3.3 浏览器 Profile 的创建与登录态保持
这是整个项目稳定运行的基石。 绝对不要 尝试在自动化脚本中处理登录流程(输入账号、密码、短信验证码)。正确做法是创建一个独立的、持久的浏览器用户数据目录(Profile),并手动完成一次完整的登录。
# 为番茄后台创建一个独立的浏览器 profile 目录
mkdir -p ~/browser-profiles/fanqie
然后,通过命令行启动 Chrome 或 Chromium 浏览器,指向这个 profile:
# 使用 Google Chrome
google-chrome --user-data-dir=/home/author/browser-profiles/fanqie --no-first-run
# 或使用 Chromium
chromium --user-data-dir=/home/author/browser-profiles/fanqie --no-first-run
注意 :
--no-first-run参数可以避免浏览器首次启动时的欢迎页面,让你直接进入一个干净的 profile 环境。
浏览器启动后:
- 手动访问番茄小说作者后台(https://author.fanqienovel.com)。
- 完成账号、密码、短信验证码等所有登录步骤。
- 成功登录后,可以随意浏览一下后台,确保登录态正常。
- 关闭浏览器。
关键验证步骤 :再次使用相同的命令启动浏览器,如果能够直接打开已登录的番茄作者后台首页,而无需重新登录,说明 Profile 创建成功且登录态已持久化保存。未来,你的自动化脚本(OpenClaw/Playwright)就需要指定使用这个 --user-data-dir 路径来启动浏览器,从而继承这个已经登录的会话。
4. 核心工作流程详解与配置
4.1 章节数据准备:从文稿到结构化输入
假设你的小说章节是用 Markdown 格式管理的,存放在 ~/novels/我的小说/ 目录下。你需要将内容转换为工具包能识别的 JSON 格式。
首先,复制模板文件:
cp chapter.template.json chapter-12.json
然后,编辑 chapter-12.json 。一个充实的示例如下:
{
"book_name": "我在仙界搞基建",
"chapter_title": "第12章 夜雨将至,护山大阵初显威",
"chapter_body": "林玄立于青云峰之巅,衣袖在凛冽的山风中猎猎作响。远处天际,墨色的劫云正以肉眼可见的速度汇聚,翻滚的云层中,隐约有紫色的电蛇游走。\n\n他深吸一口气,指尖在虚空中快速划动,一道道泛着微光的灵纹随之浮现,融入脚下早已刻画好的阵基之中。‘乾坤逆转阵’的最后一道枢纽,正在被缓缓激活。\n\n“来了。”他低声自语,目光锁定云层最深处那道骤然亮起的雷光。",
"action": "prepare_draft",
"publish_time": "",
"source_file": "/home/author/novels/我在仙界搞基建/chapters/12.md",
"notes": "本章为关键战斗场景转折点。发布前需重点检查:1. 阵法描述术语是否前后统一;2. 雷劫威力描写的梯度感;3. 主角心理活动段落是否过于冗长。"
}
实操要点 :
chapter_body中的换行符\n会被正确解析,保持你在 Markdown 中的段落格式。action字段目前填写prepare_draft,表示“准备草稿”。这是最安全、最常用的动作。source_file务必使用 Linux 的绝对路径,这是为了日志的绝对可追溯性。notes字段是你的私人检查清单,不会提交给平台,但会在日志中保留,提醒你发布前需要人工核对什么。
对于批量操作,则使用 chapters.batch.template.json ,它可以为同一本书的多个章节统一设置 book_name 和 default_action 。
4.2 页面元素定位策略(Selectors)配置
这是自动化脚本的“眼睛”。 selectors.md 文件定义了如何找到页面上的各个按钮和输入框。番茄后台的页面结构可能会更新,因此这里的配置可能需要你在联调时校准。
你需要打开浏览器开发者工具(F12),使用元素选择器来定位。例如,找到“新建章节”按钮:
// 在 selectors.md 中,你可能会定义:
新建章节按钮: “button:has-text('新建章节')” 或 “.create-chapter-btn”
更稳健的做法是使用多重定位策略。项目骨架已经为你规划好了需要定位的关键节点:
- 后台首页识别 :如何判断已成功进入作者工作台。
- 作品列表定位 :在有多部作品时,如何选择目标作品。
- 章节列表页的“新建”按钮 。
- 编辑器内的标题输入框 (
input[placeholder*="标题"])。 - 正文编辑器 :番茄后台很可能使用 ProseMirror 等富文本编辑器,不能简单地向
div输入文本。需要定位到可编辑的contenteditable区域,示例脚本中展示了如何使用page.evaluate来注入文本。 - 保存草稿按钮 (
button:has-text('保存草稿'))。 - 发布按钮 及 发布确认弹窗 。
重要经验 :不要使用绝对且易变的 CSS 路径,如 #root > div > div:nth-child(2) > button 。优先使用按钮的文本内容、具有辨识度的 class 名称或 data-testid 等属性。将联调确认后的选择器,更新到 selectors.md 文件中。
4.3 浏览器工作流(Browser Workflow)编排
browser-workflow.md 文件定义了自动化的“剧本”。它详细描述了从启动浏览器到完成操作的每一个步骤,以及每个步骤成功、失败或停止的条件。
一个典型的流程段落如下:
步骤 1.0: 导航至章节列表页
- 操作: 点击作品管理菜单,等待章节列表加载。
- 成功条件: 页面 URL 包含 “/chapter/list”,且出现“新建章节”按钮。
- 失败条件: 超时(30秒)未加载出列表。
- 停止条件: 检测到“账号未登录”提示页。
- 截图检查点: 导航完成后截图,命名为 “step1_chapter_list.png”。
你需要根据 selectors.md 中的定位信息,和你在真实页面操作的经验,来填充和完善这个工作流文件。它应该详尽到足以让一个不熟悉流程的人也能看懂机器要做什么、以及如何判断对错。
4.4 执行策略与安全边界设定
execution-policy.md 文件是项目的“交通规则”和“保险丝”。它定义了各种策略,确保自动化行为在安全可控的范围内:
- 超时策略 :每个页面加载、元素查找操作设置合理的超时时间(如 30秒),防止脚本因网络卡顿而无限等待。
- 重试策略 :对于非关键性的临时失败(如网络波动导致的点击失败),可以重试1-2次。
- 发布策略 : 核心安全策略 。必须明确规定,只有在人工通过特定指令(如聊天命令
确认发布)明确确认后,才能执行publish动作。脚本自身在任何情况下都不应自动决定发布。 - 截图策略 :规定在每一个关键节点(进入后台、打开编辑器、保存草稿后)都必须截图,并保存到
screenshots/目录,以时间戳和步骤命名。这是最直观的故障排查证据。 - 最小输出约定 :无论成功与否,每次运行都必须生成结构化的日志输出(遵循
output.schema.json),至少包含状态码、消息、相关截图路径和错误信息(如果有)。
5. 真实环境联调与测试实战
5.1 首次联调校准清单
在一切就绪后,不要直接用你的小说正文进行测试。首先,严格按照 real-site-calibration-checklist.md 文件的指引,进行一次“空跑”联调。
- 创建测试章节 :在番茄后台手动创建一个名为
【测试】联调专用章的章节,正文写一些无意义的文字(如“测试正文”)。 - 运行校准脚本 :使用
chapter.example.json(或你自己修改的测试 JSON),将action设置为prepare_draft,指向一个测试用的正文文件。 - 逐步验证 :观察自动化脚本是否能:
- 成功打开浏览器并进入已登录的后台。
- 正确导航到你的作品和章节列表。
- 点击“新建章节”(或找到你刚才创建的测试章进行编辑)。
- 将你 JSON 中定义的标题和正文,准确无误地填入编辑器。
- 点击“保存草稿”按钮。
- 检测到“保存成功”的提示(可能是页面提示,也可能是 URL 变化)。
- 记录与修正 :这个过程一定会遇到问题,比如元素定位失败、编辑器输入不生效等。打开开发者工具,重新确认选择器,并更新到
selectors.md和browser-workflow.md中。 每解决一个问题,就记录一条到校准清单里 。
5.2 执行测试用例验证核心流程
联调通过后,运行项目预置的测试用例 ( test-cases.md )。从最核心、最安全的用例开始:
- TC-001 单章草稿保存成功 :验证最基本的“填内容-存草稿”流程。
- TC-002 发布前检查成功 :验证脚本能成功触发发布前的检查页面(但不点击最终发布)。
- TC-005 未登录时正确停止 :关闭浏览器 Profile 的登录态,或使用一个新 Profile,验证脚本能检测到未登录状态并优雅停止,而不是疯狂点击或报错。
- TC-009 编辑器未接受正文时正确停止 :模拟编辑器加载失败的情况,验证脚本能识别并停止。
这些测试用例覆盖了成功路径和关键的失败路径,确保你的脚本不是“温室里的花朵”,而具备基本的异常处理能力。
5.3 集成到 OpenClaw 或自定义脚本
项目提供了 playwright-fanqie-publish-example.js 作为技术实现的参考。如果你使用 OpenClaw,需要根据其特定的技能(Skill)格式,将 SKILL.md 、 templates/ 和 scripts/ 下的内容进行适配。
如果你选择自行编写 Node.js 脚本,可以参考以下极简骨架,集成 Playwright 和你的配置文件:
const { chromium } = require('playwright');
const fs = require('fs').promises;
(async () => {
// 1. 加载配置和输入数据
const config = JSON.parse(await fs.readFile('./execution-policy.json', 'utf-8'));
const inputData = JSON.parse(await fs.readFile('./chapter-12.json', 'utf-8'));
const selectors = JSON.parse(await fs.readFile('./selectors.json', 'utf-8'));
// 2. 启动浏览器,使用固定的已登录 Profile
const browser = await chromium.launchPersistentContext('/home/author/browser-profiles/fanqie', {
headless: false, // 首次调试建议设为 false,方便观察
timeout: config.timeouts.pageLoad
});
const page = await browser.newPage();
// 3. 导航至番茄作者后台
await page.goto('https://author.fanqienovel.com');
// 这里应添加根据 selectors 判断是否登录成功的逻辑
// 4. 根据 browser-workflow.md 定义的流程,执行一系列操作
// ... (导航到作品,点击新建,填充标题和正文)
// 5. 填充正文(针对 ProseMirror 编辑器示例)
const editorSelector = selectors.bodyEditor; // 例如 '.ProseMirror'
await page.click(editorSelector);
// 先清空可能存在的默认文字(谨慎操作)
// await page.keyboard.press('Control+A');
// await page.keyboard.press('Backspace');
// 然后输入正文
await page.keyboard.type(inputData.chapter_body);
// 6. 点击保存草稿
const saveButtonSelector = selectors.saveDraftButton; // 例如 “button:has-text('保存草稿')”
await page.click(saveButtonSelector);
// 等待保存成功的反馈,可能是等待某个提示元素出现
await page.waitForSelector(selectors.saveSuccessToast, { timeout: 10000 });
// 7. 截图并记录日志
await page.screenshot({ path: `screenshots/draft_saved_${Date.now()}.png` });
const logEntry = {
timestamp: new Date().toISOString(),
book: inputData.book_name,
chapter: inputData.chapter_title,
action: inputData.action,
status: 'draft_saved',
screenshot: `screenshots/draft_saved_${Date.now()}.png`
};
await fs.appendFile(`logs/publish_${Date.now()}.jsonl`, JSON.stringify(logEntry) + '\n');
// 8. 如果是 review 动作,则导航到发布确认页,但停住,等待人工
if (inputData.action === 'review') {
await page.click(selectors.publishButton);
await page.waitForSelector(selectors.confirmDialog);
console.log('已进入发布确认页面,请人工检查后确认。');
// 此处脚本可以暂停,或进入一个等待循环,监听外部指令(如来自聊天机器人的“确认发布”命令)
}
// 9. 清理
await browser.close();
})();
6. 常见问题排查与运维心得
6.1 元素定位失败:页面结构又变了!
这是最常见的问题。 症状 :脚本报告找不到按钮或输入框,超时退出。
- 排查 :立即手动打开浏览器,使用相同的 Profile 访问页面,用开发者工具检查之前定义的选择器是否还能找到元素。
- 解决 :更新
selectors.md文件。寻找更稳定的定位方式,例如:- 使用包含部分文本的匹配:
button:has-text("保存")。 - 使用元素属性组合:
button[class*="save-btn"][type="button"]。 - 如果平台给关键元素添加了
data-testid,一定要用它,这是最稳定的。
- 使用包含部分文本的匹配:
- 预防 :在
browser-workflow.md中,为每个关键步骤设置 备用选择器 和 截图点 。当主选择器失败时,尝试备用方案,并无论如何都截图,供事后分析。
6.2 编辑器内容填充不上
症状 :标题填好了,但正文编辑器里是空的,或者只输入了第一个字。
- 原因 :富文本编辑器(如 ProseMirror、Quill)通常不是一个简单的
input或textarea,而是contenteditable的div。直接page.type()可能焦点不对。 - 解决 :
- 确保先点击编辑器区域 (
page.click(editorSelector)) 激活焦点。 - 使用
page.keyboard.type()方法模拟真实键盘输入,虽然慢但最可靠。 - 对于大段文本,可以考虑使用
page.evaluate()直接设置编辑器内部的 HTML 内容,但这需要精确了解编辑器的内部 DOM 结构,风险较高。 首选方案是page.keyboard.type()。 - 在输入后,等待编辑器自身的字数统计或状态更新,作为“输入完成”的判断依据。
- 确保先点击编辑器区域 (
6.3 登录态丢失或风控拦截
症状 :脚本打开浏览器后,被跳转到登录页,或出现验证码。
- 排查 :
- 检查浏览器 Profile 目录是否被其他进程占用或损坏。
- 检查网络 IP 地址是否发生剧烈变动。
- 近期是否在脚本中执行了过于频繁的请求?
- 解决 :
- 绝对不要 在脚本中自动处理验证码。这是红线。
- 脚本应检测到登录页或验证码页面,立即停止,并记录错误日志和截图。
- 人工介入:用同一个 Profile 手动登录一次,解决风控问题(可能需要手机验证)。
- 优化行为:在
execution-policy.md中增加操作之间的随机延迟,模拟人类操作间隔,降低风控概率。
6.4 批量处理中的错误恢复
症状 :批量处理10章,第5章失败了,整个任务停止。
- 期望 :第5章失败,记录详细错误到日志,跳过它,继续处理第6章。
- 实现 :在你的批量处理脚本逻辑中,对每个章节的处理流程使用
try...catch包裹。在catch块中,记录错误信息、截图,然后继续循环。最终输出一份报告,说明哪些成功、哪些失败及原因。
6.5 日志与截图管理
随着使用时间增长, logs/ 和 screenshots/ 目录会越来越大。
- 建议 :编写一个简单的清理脚本,定期(如每周)归档旧的日志和截图。可以按日期打包压缩。
- 日志分析 :结构化日志(JSON Lines 格式)的好处是可以方便地用
jq等工具进行分析。例如,快速统计本月成功保存草稿的章节数:grep \"draft_saved\" logs/*.jsonl | wc -l。
这个工具包的价值不在于实现完全的黑盒魔法,而在于提供一套严谨、可维护、安全的人机协作框架。它要求你作为使用者,也需要深入理解流程的每个环节,并在关键节点保持掌控力。通过这种方式,你不仅获得了一个效率工具,更建立起一套关于内容发布自动化的可靠工程实践。当番茄后台的页面未来再次改版时,你完全可以依据这个框架和积累的经验,快速调整选择器和工作流,让工具重新为你服务。
更多推荐




所有评论(0)