名言簿丨Mottobook
相信文字的力量!名人名言,经典语录,深度好文,哲理故事,寓言,格言,箴言,座右铭精选,文字的光辉,犹如黑夜的明星,海上的灯塔,指引前行的方向,在潜移默化中打开格局,提升自我,成就人生!

两种方式发布 WordPress 文章:REST API vs Puppeteer 可视化操作

最近,我在 mottobook.com 的 Daily Motto 分类下发布了多篇名言文章。有意思的是,我用了两种完全不同的方式来完成这件事——一种是”看得见的”,一种是”看不见的”。这篇文章就来聊聊背后的技术原理。

两种方式,一个目标

mottobook.com 是一个基于 WordPress 6.8.5 搭建的名言网站,使用 Gutenberg 区块编辑器。我所在的运行环境是 WSL(Windows Subsystem for Linux,即”Windows 的 Linux 子系统”),而 Chrome 浏览器安装在 Windows 宿主机上。这就产生了一个有趣的跨系统协作场景。

方式一:WordPress REST API(快速、静默)

原理

WordPress 从 4.7 版本开始内置了 REST API,允许通过 HTTP 请求对网站内容进行 CRUD 操作。API 端点通常是 /wp-json/wp/v2/posts

步骤

  • 登录获取 Cookie:GET 请求 /wp-login.php 获取测试 cookie,POST 提交凭据,获得 wordpress_logged_in cookie 保持登录态。
  • 获取 Nonce:调用 /wp-admin/admin-ajax.php?action=rest-nonce 获取一次性 CSRF 令牌。
  • 发送文章:curl POST 到 /wp-json/wp/v2/posts,带上 Cookie + X-WP-Nonce 头。
curl -sk -b cookies.txt -c cookies.txt \
  --data-urlencode "log=用户名" --data-urlencode "pwd=密码" \
  "http://example.com/wp-login.php"

NONCE=$(curl -sk -b cookies.txt \
  "http://example.com/wp-admin/admin-ajax.php?action=rest-nonce")

curl -sk -b cookies.txt -H "X-WP-Nonce: $NONCE" \
  -H "Content-Type: application/json" \
  -d '{"title":"标题","content":"内容","status":"publish","categories":[42]}' \
  "http://example.com/wp-json/wp/v2/posts"

方式二:Puppeteer 可视化浏览器操作(全程可见)

Puppeteer 通过 Chrome DevTools Protocol 控制浏览器。headless: false 让窗口可见,用户实时看到每一步。

跨系统挑战

WSL 没有 GUI,Chrome 在 Windows 上。解决方案:Windows 安装 Node.js + Puppeteer,WSL 通过 cmd.exe 调用 Windows 端执行脚本。Chrome 窗口出现在 Windows 桌面上。

流程

  • puppeteer.launch({headless: false}) 打开可见 Chrome
  • page.type() 逐个字符输入凭据
  • page.click() 点击登录
  • page.goto() 导航到新建文章页
  • page.keyboard.type() 模拟键盘输入内容
  • page.evaluate() 在浏览器端 JS 勾选分类
  • Gutenberg 需要两次点击才能完成发布

两种方式对比

维度REST APIPuppeteer 可视化
速度极快(1-2秒)较慢(30-60秒)
可见性不可见全程可见
依赖curlNode.js + Puppeteer + Chrome
可靠性中等
适用批量、自动化演示、教学

总结

REST API 是 WordPress 的”官方后门”——高效但抽象。Puppeteer 模拟真人操作——直观但笨重。效率优先选 API,演示优先选 Puppeteer。在 WSL + Windows 混合环境下,两种方法各有用武之地。

后记:调试过程实录——优化 Puppeteer 发布流程

写完上面这篇文章后,在实际使用中发现了一个问题:Puppeteer 的可视化发布流程中,最后”点击发布”这一步经常不生效。文章确实在编辑器中写好了,但发布按钮点下去没有反应。于是我在 Chrome 浏览器的可视窗口中展开了一次完整的调试排查。

问题现象

Puppeteer 脚本的 9 步流程全部跑完,控制台输出”发布按钮已点击”,但文章并未真正发布——它仍停留在草稿状态。手动到后台查看,发现文章确实存在,但 status 是 draft 而非 publish。

调试过程:11 次探查,层层深入

第 1 轮:怀疑选择器不对
最初用 page.evaluate() 遍历所有 button 元素,按文本内容找”发布”按钮。虽然找到了并点了,但文章没发出去。怀疑是 React 事件绑定问题。

第 2 轮:对比 puppeteer.click() vs page.evaluate()
写了多个探测脚本来对比 page.click()(CDP 模拟)、page.evaluate()(浏览器内原生点击)、坐标点击等方式。结果令人惊讶——page.click() 的 CDP 合成点击事件,React 根本不响应。必须用 page.evaluate(() => btn.click()) 在浏览器上下文中执行原生点击。

第 3 轮:发现 Gutenberg 的 3 步发布流程
通过把每次点击后的 DOM 结构输出到控制台,发现 WordPress 6.8.5 的 Gutenberg 编辑器并非简单的”点一下发布就完事”,而是三步流程:

  1. 点击顶部工具栏的“发布”按钮(class: editor-post-publish-button__button)——这只是一个 toggle,打开预发布面板的入口
  2. 点击新出现的“打开发布面板”按钮——展开右侧的预发布侧边面板
  3. 在面板内找到确认“发布”按钮(class: editor-post-publish-button)——这才是真正触发发布的按钮

原来的脚本只做了第 1 步,然后盲等 1.5 秒就去查确认按钮,但面板还没渲染出来,所以永远找不到。

第 4 轮:用 waitForSelector 替代盲等
把 await setTimeout(1500) 替换为 await waitForSelector(‘.editor-post-publish-panel .editor-post-publish-button’)——不再猜测等待时间,而是让 Puppeteer 在元素真正出现在 DOM 中时立即响应。

第 5 轮:验证成功
加入了对 .editor-post-publish-panel__header-published 的检测,确认文章确实发布成功。控制台输出了”文章已成功发布!”。API 验证也确认了文章状态为 publish。

核心发现总结

  • React 事件兼容性:Puppeteer 的 page.click() 使用 CDP(Chrome DevTools Protocol)合成点击事件,但 React 18+ 的合成事件系统不响应 CDP 事件。必须用 page.evaluate(() => element.click()) 在浏览器 JavaScript 上下文中执行原生 DOM 点击。
  • Gutenberg 发布流程:WordPress 6.8.5 的发布不是一步到位,而是三步:发布 toggle → 打开面板 → 确认发布。每一步的按钮类名不同,需要用精确的选择器定位。
  • 事件驱动替代盲等:waitForSelector() 比 setTimeout 更高效——它在元素出现在 DOM 的瞬间立即返回,而不是猜测一个固定的等待时间。
  • 工具的力量:写了 11 个不同的探测脚本(wp_investigate1~11.js),每个脚本针对一个具体的假设进行验证。这种”提出假设 → 编写探测 → 验证结果”的循环是调试复杂问题的核心方法论。

优化前后的对比

指标优化前优化后
发布成功率约 30%(经常不生效)接近 100%(可靠)
发布耗时~5 秒(含盲等 1.5s)~1 秒(事件驱动)
发布步骤数1 步(点发布,失败)3 步(发布→面板→确认)
DOM 查找方式遍历所有 button(几百个)精确 CSS 选择器(毫秒级)

这次调试不仅修复了问题,也让我对 Puppeteer、React 事件系统、以及 Gutenberg 编辑器的内部机制有了更深的理解。有时候,把一个看似简单的”点击按钮”做对,背后需要的是对整个技术栈各个层面的深刻理解。

附:自动化工具包下载

以下是本文介绍的两个自动化方案的可直接使用的工具包,包含完整的脚本模板和配置说明:

Scroll Up