浏览器自动化的五个隐形坑:从 React 输入框到后台标签节流
为什么写这个
这周做浏览器自动化,本以为最难的是登录和抓包,结果时间全花在了几个「看起来很简单」的组件上:一个富文本编辑器、一个标签选择器、一个带追踪参数的跳转链接。
这篇把踩过的五个坑记下来,都是能直接复用的经验。
坑一:给 React 输入框赋值,改 value 没用
最常见的失败:这样写,页面上字都出来了,但点提交时提示「请填写标题」。
input.value = '我的标题';
input.dispatchEvent(new Event('input', { bubbles: true })); // 仍然无效
原因是 React(以及 Vue 的某些版本)在 DOM 上挂了自己的 value 追踪器,直接赋值会被它认为是「值没变」而跳过更新。
正确的写法是拿到原型链上的原生 setter,绕过那层拦截:
const desc = Object.getOwnPropertyDescriptor(
HTMLInputElement.prototype, 'value'
);
desc.set.call(input, '我的标题');
input.dispatchEvent(new Event('input', { bubbles: true }));
判断标准:如果页面上看得见文字、但提交时校验不通过,基本就是这个原因。
坑二:富文本编辑器的内容在 iframe 里
文章编辑器、评论框这类组件,正文往往不是 textarea,而是一个 contenteditable 的 iframe。直接对 iframe 外层的元素操作是无效的。
要进到文档内部写:
const doc = iframe.contentDocument;
doc.body.innerHTML = '<p>正文第一段</p><p>第二段</p>';
doc.body.dispatchEvent(new Event('input', { bubbles: true }));
doc.body.dispatchEvent(new Event('blur', { bubbles: true }));
两个细节:
- 光设
innerHTML不够,还得派发input和blur,否则编辑器内部的模型不更新,提交上去是空的; - 有些页面还会同步一个隐藏
textarea作为真实提交字段,需要一起赋值。
坑三:自定义标签选择器,看得见不等于填上了
这类组件(常见 class 名带 tagator、tags-input)会把选中的标签渲染成一排小方块,但真正提交的值在一个独立 input 里。你看到方块出现了,不代表表单收到了值。
验证方法很简单,去 DOM 里找那个真实字段:
document.querySelector('input#input-tag').value // 这里才是真值
如果这里是空的,说明你只是「看起来选中了」。补法通常是键盘路径:输入关键词 → ArrowDown → Enter,让组件走它自己的选择逻辑。
坑四:target="_blank" 的链接,点了没反应
自动化点击常常遇到这种情况:元素找到了、坐标也对、点了,但什么都没发生。因为浏览器要求 target="_blank" 由真实用户手势触发,脚本合成的 element.click() 会被弹窗拦截器拦掉。
解法不是硬点,而是把链接取出来自己打开:
const href = document.querySelector('a').href;
// 新建标签页后带 referrer 导航
await page.navigate(href, { referrer: 'https://来源页面域名/' });
注意 referrer 这一步。很多带追踪参数的链接会校验来源,不带就白跳。
坑五:后台标签页会被节流
这个坑最隐蔽。页面在后台时,浏览器会把定时器降到每分钟一次甚至暂停,依赖心跳上报的「活跃度」类任务就永远不触发。
表现是:你明明打开了页面、操作也做了,但后端就是不认。而每次你切回去检查,它又变成前台——检查动作本身把状态搞乱了。
处理办法:
- 执行关键动作后,把目标标签切到前台并保持,中途不要切走;
- 需要看结果时,用接口查询而不是切页面;
- 实在要切,就接受「可能失败」,隔一段时间重试一次。
小结
这五个坑有个共同点:都不是「找不到元素」,而是「以为成功了其实没生效」。所以判断标准不能是「界面上有变化」,而要找那个真正被提交的字段或接口。
一个实用的习惯:每步操作后,去查一次真实值(DOM 里的隐藏字段、或者一次接口调用),别靠肉眼判断。这比事后调试省太多时间。
- 点赞
- 收藏
- 关注作者
评论(0)