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 这两个模板文件,定义了工具需要知道的一切:作品名、章节标题、正文内容、要执行的动作、源文件路径以及备注信息。

这种设计的好处是多方面的:

  1. 可追溯 source_file 字段记录了章节内容的来源,方便回溯和对照。
  2. 可批量 :批量模板允许一次性准备多个章节,极大地提升了准备效率。
  3. 可校验 :配套的 input.schema.json 文件定义了数据格式的规范,可以在执行前进行有效性检查,避免因数据格式错误导致流程中断。
  4. 职责分离 :作者只需要关心内容(编辑好 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

执行后,脚本会:

  1. 检查 manifest.json SKILL.md 等核心文件是否存在。
  2. 创建 logs/ screenshots/ 目录,用于存放运行日志和过程截图。
  3. 输出后续的联调建议。 如果一切顺利,你会看到类似“初始化完成,请开始联调”的提示。 重要提示 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 环境。

浏览器启动后:

  1. 手动访问番茄小说作者后台(https://author.fanqienovel.com)。
  2. 完成账号、密码、短信验证码等所有登录步骤。
  3. 成功登录后,可以随意浏览一下后台,确保登录态正常。
  4. 关闭浏览器。

关键验证步骤 :再次使用相同的命令启动浏览器,如果能够直接打开已登录的番茄作者后台首页,而无需重新登录,说明 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”

更稳健的做法是使用多重定位策略。项目骨架已经为你规划好了需要定位的关键节点:

  1. 后台首页识别 :如何判断已成功进入作者工作台。
  2. 作品列表定位 :在有多部作品时,如何选择目标作品。
  3. 章节列表页的“新建”按钮
  4. 编辑器内的标题输入框 ( input[placeholder*="标题"] )。
  5. 正文编辑器 :番茄后台很可能使用 ProseMirror 等富文本编辑器,不能简单地向 div 输入文本。需要定位到可编辑的 contenteditable 区域,示例脚本中展示了如何使用 page.evaluate 来注入文本。
  6. 保存草稿按钮 ( button:has-text('保存草稿') )。
  7. 发布按钮 发布确认弹窗

重要经验 :不要使用绝对且易变的 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 文件的指引,进行一次“空跑”联调。

  1. 创建测试章节 :在番茄后台手动创建一个名为 【测试】联调专用章 的章节,正文写一些无意义的文字(如“测试正文”)。
  2. 运行校准脚本 :使用 chapter.example.json (或你自己修改的测试 JSON),将 action 设置为 prepare_draft ,指向一个测试用的正文文件。
  3. 逐步验证 :观察自动化脚本是否能:
    • 成功打开浏览器并进入已登录的后台。
    • 正确导航到你的作品和章节列表。
    • 点击“新建章节”(或找到你刚才创建的测试章进行编辑)。
    • 将你 JSON 中定义的标题和正文,准确无误地填入编辑器。
    • 点击“保存草稿”按钮。
    • 检测到“保存成功”的提示(可能是页面提示,也可能是 URL 变化)。
  4. 记录与修正 :这个过程一定会遇到问题,比如元素定位失败、编辑器输入不生效等。打开开发者工具,重新确认选择器,并更新到 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() 可能焦点不对。
  • 解决
    1. 确保先点击编辑器区域 ( page.click(editorSelector) ) 激活焦点。
    2. 使用 page.keyboard.type() 方法模拟真实键盘输入,虽然慢但最可靠。
    3. 对于大段文本,可以考虑使用 page.evaluate() 直接设置编辑器内部的 HTML 内容,但这需要精确了解编辑器的内部 DOM 结构,风险较高。 首选方案是 page.keyboard.type()
    4. 在输入后,等待编辑器自身的字数统计或状态更新,作为“输入完成”的判断依据。

6.3 登录态丢失或风控拦截

症状 :脚本打开浏览器后,被跳转到登录页,或出现验证码。

  • 排查
    1. 检查浏览器 Profile 目录是否被其他进程占用或损坏。
    2. 检查网络 IP 地址是否发生剧烈变动。
    3. 近期是否在脚本中执行了过于频繁的请求?
  • 解决
    1. 绝对不要 在脚本中自动处理验证码。这是红线。
    2. 脚本应检测到登录页或验证码页面,立即停止,并记录错误日志和截图。
    3. 人工介入:用同一个 Profile 手动登录一次,解决风控问题(可能需要手机验证)。
    4. 优化行为:在 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

这个工具包的价值不在于实现完全的黑盒魔法,而在于提供一套严谨、可维护、安全的人机协作框架。它要求你作为使用者,也需要深入理解流程的每个环节,并在关键节点保持掌控力。通过这种方式,你不仅获得了一个效率工具,更建立起一套关于内容发布自动化的可靠工程实践。当番茄后台的页面未来再次改版时,你完全可以依据这个框架和积累的经验,快速调整选择器和工作流,让工具重新为你服务。

Logo

小龙虾开发者社区是 CSDN 旗下专注 OpenClaw 生态的官方阵地,聚焦技能开发、插件实践与部署教程,为开发者提供可直接落地的方案、工具与交流平台,助力高效构建与落地 AI 应用

更多推荐