用 CDP 驱动常驻 headless Chrome:网页自动化踩坑实录

举报
yd_297054392 发表于 2026/10/30 03:22:34 2026/10/30
【摘要】 在资源受限的服务器上用常驻 headless Chrome + CDP 做网页自动化,会遇到白屏不 hydrate、CDP 超时、标签页泄漏、登录态失效等六个典型问题,这里给出可复用的排查与规避办法。

在只有 2 vCPU、不到 2GB 可用内存的服务器上跑网页自动化,最容易犯的错就是"每次任务新开一个浏览器"。我在这台机器上把模式改成:一个常驻的 headless Chrome(systemd 托管、固定 user-data-dir、固定调试端口 9222),所有脚本都通过 Chrome DevTools Protocol 连上去复用同一批标签页。下面是这套方案踩过的六个坑和对应解法。

一、为什么不再"用完即关"

三个理由:

  • 冷启动成本:headless Chrome 冷启动加首次渲染通常要几秒,一天跑十几次任务,纯等待时间就很可观;
  • 登录态:每次用新的 profile,站点会当成新设备;固定 profile 才能让 Cookie 长期存活;
  • 内存:这是一台 2 vCPU / 1.7GB RAM 的机器,网关服务常驻就占掉 800MB 上下,同时起多个浏览器实例很容易打满内存。

所以做法是:浏览器只起一次并交给 systemd Restart=always 托管,脚本只负责建标签页、操作、关标签页。

二、坑 1:页面一片空白,按钮全部 disabled

这是最迷惑的一类故障:标题出来了、document.body.innerText 有内容,但按钮点不动,组件区是空的。

原因是 headless 模式下 document.visibilityState 恒为 hidden,而 React / Next 这类做流式 SSR + 惰性 hydrate 的页面,在这个状态下往往根本不启动 hydration。

解法是导航之后显式把生命周期和焦点模拟打开,并且每次 Page.navigate 之后都要重设:

cdp('Emulation.setFocusEmulationEnabled', enabled=True)
cdp('Page.setWebLifecycleState', state='active')

三、坑 2:CDP 调用报 “timed out after 5s waiting for the daemon”

封装层给 CDP IPC 的默认超时常常只有 5 秒。普通站点够用,但遇到慢站、SSO 多次跳转、或者页面上埋点请求堆积时,5 秒很容易被打穿,而且报错信息指向"导航超时",容易误判成网络问题。

办法:对已知慢的页面单独放大超时(例如 30 秒),并且先导航、后设置可视化状态,别把两个动作的耗时叠在一次调用里。

四、坑 3:标签页泄漏

云控制台类站点的按钮很喜欢 target=_blank。一个流程跑下来攒出十几个标签页,2GB 内存直接被榨干,表现就是后续所有操作越来越慢,最后整个浏览器卡死。

我的做法是:一个任务尽量在一个标签页里完成;遇到新开的页面立刻用 Target.closeTarget 关掉;每轮任务开始前用 GET http://127.0.0.1:9222/json/list 列一遍,清理到只剩 1–2 个标签页。

五、坑 4:登录态与二次验证

用一次性 profile 登录,站点会当成新设备,短信验证码几乎必弹(有些还只发手机、邮箱收不到),自动化流程直接卡死在这一步。固定 profile + 常驻进程让 Cookie 长期存活才是关键。

真的过期了怎么办:不要把密码写进脚本。把账号口令放进凭据管理器,让工具在登录页按 origin 匹配后填充并提交。实测同一个长期使用的 profile 重新登录时不再触发短信验证,这也印证了"新 profile = 新设备"的判断。

六、坑 5:wait_for_load 不等于数据就绪

很多页面的骨架是 SSR 直接出的,真正的数据要靠前端 XHR 拉。导航完成事件触发时,你要的那个数字可能还没到。

两个更稳的做法:

  • 轮询 document.body.innerText,直到目标字符串出现(例如等待积分数字从 - 变成真实数字);
  • 直接在页面里 fetch 那个 XHR 接口,拿 JSON,比解析 DOM 稳定得多。

七、坑 6:能走接口就别爬 DOM

这条提升最大。列表类、库存类数据往往有公开的 JSON 接口,匿名即可读。与其拖 DOM、等渲染、扛改版,不如直接请求接口:

curl -s 'https://example.com/api/xxx?limit=100' | python3 -m json.tool

DOM 选择器会因为前端发版而失效,接口的字段通常稳定得多。

八、小结:一份上线前检查清单

每次写新的自动化流程前,我会先确认这几件事:

  • [ ] 浏览器是常驻的,调试端口通(curl http://127.0.0.1:9222/json/version);
  • [ ] 每次导航后重设 focus emulation 和 lifecycle state;
  • [ ] 慢站的 CDP 调用放大了超时;
  • [ ] 任务开始前后各清理一次标签页;
  • [ ] 关键数据优先走接口,其次才是轮询 DOM;
  • [ ] 凭据只从凭据管理器取,不写进代码。

这套东西本身不复杂,难的是把"浏览器是稀缺资源"这件事当成前提来设计流程。资源一旦被当成常驻服务而不是一次性消耗品,稳定性和速度都会好很多。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。