把「一文多发」做成脚本流水线:CDP、滑块、二维码、WAF、限流,这些坑我替你踩完了

把「一文多发」做成脚本流水线:CDP、滑块、二维码、WAF、限流,这些坑我替你踩完了

参与话题:CSDN+AI:程序员新生产力 环境:Windows 11 + Chrome + CDP(remote-debugging-port)+ Node.js。全自动不现实、纯手动又太低效,本篇讲的就是那条「半自动流水线」怎么搭起来、坑都在哪。

一、先交代背景:为什么要做这件事

我在县级生态环境部门做行政处罚办案。今年 9 月起写了一个七篇的系列稿(《生态环境法典》1242 条的知识库化 + 执法文书 AI 实战),要在 6 个平台同步发布:CSDN、掘金、思否、51CTO、知乎、博客园。

手动发一遍是什么体验?打开编辑器、贴正文、等图片转存、填标签、传封面、写摘要、点发布、扫码确认------一个平台 20 分钟,六个平台两小时起步,而且每一步都可能掉链子:滑块验证码、登录态过期、图片外链被防盗链掐死、发布按钮点不动。

所以我把整条流水线脚本化了。现在是:正文 md 在本地,一条命令从打开编辑器到出二维码,人只需要拿手机扫一次码。 单平台操作时间从 20 分钟压到 3 分钟以内。

这篇不讲「怎么用某个自动化框架」,讲的是这一路上真实踩过的坑和对应的解法。全部代码片段都可以直接搬走用。

二、架构:为什么是 CDP 而不是 Playwright

第一版用的是 Playwright,两天就放弃了。原因很朴素:

  1. 各平台的编辑器全是重前端(CodeMirror、Draft.js、Tiptap),Playwright 的 fill() 对它们经常不生效,最后都得绕回 evaluate 里拿真实对象操作;
  2. 风控对自动化浏览器的识别很敏感,Playwright 的部分指纹过不了滑块;
  3. 我需要复用日常浏览器的登录态------每天开 WorkBuddy、微信、各种后台都在同一个 Chrome profile 里,重新登录一遍的成本比写代码还高。

最终方案:手动开一个带调试端口的 Chrome,脚本通过 CDP(Chrome DevTools Protocol) WebSocket 连上去操作。

bash 复制代码
# 启动带调试端口的 Chrome(9333)
start chrome.exe --remote-debugging-port=9333 --user-data-dir="D:/cdp-profile" --no-first-run
js 复制代码
// 最小连接骨架:列出标签页 → 按 URL 选中目标 → 双向 WebSocket
const list = await (await fetch('http://127.0.0.1:9333/json/list')).json();
const tab = list.find(t => t.type === 'page' && /editor\.csdn\.net/.test(t.url));
const ws = new WebSocket(tab.webSocketDebuggerUrl);
const send = (method, params) => { /* id 配对 + promise 封装,略 */ };
const ev = js => send('Runtime.evaluate', { expression: js, returnByValue: true });

这套骨架 40 行,后面所有平台通用。关键心法:能 Runtime.evaluate 拿到页面真实对象(如 CodeMirror 实例)就别用键盘鼠标模拟;只有逼不得已才派发输入事件。

三、坑一:Chrome 会「死」,而且死得很安静

第一个坑最阴:脚本跑一半 Chrome 没了。

原因是我用 child_process.spawn 拉起的 Chrome,父进程(Node 脚本)一退出,Chrome 跟着被系统回收。表现是上一条命令里还活着的 Chrome,下一条命令连 9333 就 connection refused,而且没有任何报错指向这个原因。

解法很蠢但有效:启动 Chrome 和操作脚本必须塞进同一个 shell 命令里 ,用 && 串死:

bash 复制代码
start chrome.exe --remote-debugging-port=9333 ... ; sleep 12 ; node my-task.js

配套的还有两个小坑:

  • 探测 CDP 活着没,curl 必须加 --noproxy '*' 。我机器上有 http_proxy=127.0.0.1:64925,不加这个参数,curl 会把 127.0.0.1:9333 的请求也丢给代理,代理自然 refused------你会误判成「Chrome 挂了」,然后白白重启一遍。
  • 计划任务拉不起带 GUI 的 Chrome 。schtasks、WMI Win32_Process.Create、PowerShell Start-Process 我全试过,不是被策略拦就是同样被回收。最后老老实实用「一条命令串到底」。

四、坑二:验证码滑块,CDP 拖必死,原生拖秒过

滑块验证码是所有自动化绕不开的墙。我试过 CDP 的 Input.dispatchMouseEvent 模拟拖动,轨迹畸长(拖 320px 用了 25 秒+)、速度均匀得像机器人,风控一秒识别。

解法:放弃 CDP 模拟,用 Python ctypes 直接调系统的 SendInput,以真实硬件级鼠标事件拖动:

python 复制代码
import ctypes, time, math

user32 = ctypes.windll.user32
user32.SetProcessDPIAware()   # 高分屏必加!否则坐标错位一半

def drag(x1, y1, x2, y2, steps=28):
    user32.SetCursorPos(int(x1), int(y1))
    time.sleep(0.25)
    user32.mouse_event(2, 0, 0, 0, 0)   # left down
    for i in range(1, steps + 1):
        t = i / steps
        # 先快后慢 + 轻微过冲回拉,模拟人手
        ease = 1 - (1 - t) ** 2.2
        jitter = math.sin(t * 9) * 1.5
        user32.SetCursorPos(int(x1 + (x2 - x1) * ease + jitter),
                            int(y1 + (y2 - y1) * ease + jitter))
        time.sleep(0.012)
    time.sleep(0.18)
    user32.mouse_event(4, 0, 0, 0, 0)   # left up

要点三条:DPI 感知 (4K 屏 1.5 倍缩放,不 SetProcessDPIAware 坐标直接错一半);轨迹先快后慢 (ease-out,人手就是这样);轻微抖动(纯正弦会太规律,叠一点随机更稳)。改造后拖 320px 用时 0.4 秒,阿里云、字节滑块全部一次过。

五、坑三:二维码只有 5 分钟命,人不在就没救

CSDN/掘金发布要微信扫码确认,二维码寿命普遍 5 分钟。人不在电脑前,出码就是浪费。

两个实战解法:

  1. 出码时机后置:把「出码」放到流程最后一刻------正文、标签、封面全部就位,发布按钮都点完了,才抓二维码。脚本同时轮询登录态,扫上就自动继续,超时(8--13 分钟)自动放弃,下一轮重来。
  2. 人不在电脑前时的杀手锏 :把二维码图片 base64 内嵌成一个静态 HTML,部署成公网页面,把链接发给自己------手机微信里打开、长按识别、确认登录,全程不需要碰电脑。这招真的成功过,能把「人必须在电脑前」这个约束彻底解掉。

六、坑四:状态判断,截图和全文正则都会骗你

自动化最怕的是「不知道操作成没成功」。我踩过三种判状态的坑:

坑 A:文章页没横幅 ≠ 没被拒。 思否(SegmentFault)审核被拒后,文章页干干净净,但通知中心躺着「发表未成功」的记录。判断必须去通知中心数条目。

坑 B:全文正则数条目会虚高。 最初我用「全文找『发表未成功』关键词 + 前后 90 字符窗口」来数被拒次数,结果窗口重叠把 2 条数成 4 条。正确做法是按 DOM 条目统计:

js 复制代码
// 每条通知是一个独立 DOM 节点,数节点不数关键词
const n = document.querySelectorAll('.stream-list-item, li.media, .list-group-item').length;

坑 C:懒加载图片假裂。 掘金文章页 img.naturalWidth === 0 不代表图裂了,可能只是还没滚到。验收图片修复要看 src 属性匹配(是否仍是会防盗链的外链域名),别看渲染结果。

七、坑五:限流规则,读不出来只能用血换

每个平台的写操作限额都不写在明面上,只能实测:

  • 掘金 :「发布 + 更新」合并计数,撞 err_no:1012 就是当日额度用尽,重试只会更糟。实测一天 3 次写操作(发+改+删)没触发,但保守按 1 篇/天排期。
  • 思否 :同一篇文章累计 3 次审核不通过自动删除 ------而且是按篇计数,不是按账号。所以改稿重提要慎重,最后一发留给最有把握的版本;真被删了,重新发一篇就是全新额度。
  • CSDN:每天限 2 篇,一天 1 篇最稳;二维码寿命约 5 分钟,发布面板要点两次(外层「发布文章」只打开面板)。

限流的应对策略只有一条:把「重试」从代码里删掉。 失败就留给下一个定时轮次,绝不当场硬刚------硬刚一次,可能赔掉整个账号。

八、坑六:依赖会「自己升级」

Node 由客户端托管时会被静默升级 (22.22.2-3 → 22.22.2-6),所有把版本号写死在配置里的定时任务一夜全哑。解法是在每个脚本入口加自愈:

bash 复制代码
NODE=$(ls -d /path/to/node/versions/*/node.exe 2>/dev/null | tail -1)

同类问题:任务有 validUntil,过期会静默停跑不报错------定期巡检必须包含「任务还活着吗」这一项。

九、收益清单

项目 脚本化前 脚本化后
单平台发布耗时 ~20 min <3 min(人工只剩扫码)
六平台全量同步 半天 2 天内分批完成,零遗漏
滑块验证码通过率 ~0%(CDP 拖动) ~100%(原生拖动)
状态误判导致的重复提交 频繁 0(DOM 断言 + 幂等设计)

阅读量顺带交代:六平台合计外部阅读约 2,000,其中 CSDN 占绝对大头(自然搜索流量),掘金/51CTO/知乎基本零分发------数据也反过来证明:该精耕的平台和该放弃的平台,发布完一周就能看出来。

十、写在最后

这套流水线没有用到任何黑科技:CDP、ctypes、一个 WebSocket 骨架、十几个平台的专用脚本。它的价值在于把「人肉流程」变成「人只出现在必须出现的地方」------目前人只剩两个动作:拿起手机扫码,和决定今天发哪篇。

下一步想把「发哪篇」也交给调度器:按各平台限流额度 + 队列状态自动排期,失败自动顺延。等跑稳了再来写下半篇。

(完)


环境备注:Windows 11 / Chrome 155 / Node 22.x / Python 3.13。文中所有脚本均为本地自用,如需完整版可以评论区留言。

相关推荐
用户8425581308744 分钟前
同一篇稿子发到 6 个平台,为什么只有这里的图片全裂了?
ai编程
猛犸象限1 小时前
【Grok Bot 仓颉实践】 编译通过了,我没让它合并——验证和证据我怎么卡
ai编程
小鱼儿亮亮1 小时前
大模型调用的演进与架构全景解析:从 cURL 原语、多维技术栈、API 规范到 LangChain 生产级实战
ai编程
用户842558130871 小时前
Chrome 自动化「点了没反应」:5 个真实坑与一套排查法
ai编程
tz_zs2 小时前
【AI编程】使用笔记:Rule/Skill/Prompt
笔记·prompt·ai编程
tz_zs3 小时前
【AI编程】使用笔记:AI编程项目文档体系与框架
笔记·ai编程
Shockang12 小时前
OpenCode 版 OmO:职责分工、编辑校验与技能边界
ai编程
小虎AI生活13 小时前
ChatGPT for Chrome 扩展升级解读:从「你复制给它」到「替你操作浏览器」(附三步上手流程)
aigc·ai编程
金銀銅鐵13 小时前
[Java] 借助GUI展示class文件的内容(v1.0版本)
jvm·后端·ai编程