为了让你清晰理解,我将模拟输入的方法按照**从上层(软件/应用层)到底层(硬件/驱动层)**进行分级和对比:
这是最原始的方法。通过在浏览器的控制台或通过 page.evaluate() 执行 JS 代码。
- 代码示例:
document.getElementById('login-btn').click() - 原理: 直接触发 HTML 元素的事件。
- 检测风险: 极高 (100% 被抓)。
- 事件的
isTrusted属性会是false。 - 没有真实的鼠标移动轨迹,点击是瞬移的。
- 严格的网站直接忽略这种点击,甚至封号。
- 事件的
这是 Playwright、Puppeteer、Selenium (部分) 默认使用的方法。
- 原理: 利用 CDP (Chrome DevTools Protocol) 的
Input.dispatchMouseEvent和Input.dispatchKeyEvent接口。它告诉浏览器内核:“在这个坐标发生了一个点击”。 - 特点:
- 优点: 事件的
isTrusted属性通常为true(因为是浏览器内核触发的)。支持后台运行(Headless 模式)。 - 缺点: 默认的
page.mouse.move往往是直线移动或匀速移动,这非常像机器人。 - 检测点: 行为分析。如果不配合复杂的轨迹算法(贝塞尔曲线、抖动),很容易被行为指纹(Behavioral Biometrics)识别。
- 优点: 事件的
这是 PyAutoGUI、AutoIt、RobotJS 使用的方法。
- 原理: 调用操作系统底层的 API(如 Windows 的
user32.dll中的SendInput或SetCursorPos)。它直接控制操作系统的光标。 - PyAutoGUI 是最底层的吗? 不是。 它只是封装了操作系统的 API。
- 与 Playwright 的区别:
- PyAutoGUI 是独占屏幕的。鼠标动的时候,你不能动鼠标,否则会冲突。
- 它不识别网页内的元素坐标,只识别屏幕像素坐标。你需要先算出网页元素在屏幕的哪里(非常麻烦且不稳定)。
- 检测风险: 对于 Web 检测来说,它的真实度高于 Level 1,但如果由 API 触发,Windows 事件中可能会带有一个
LLMHF_INJECTED标记,极少数超高等级的反作弊(通常是游戏反外挂,而非网页)能检测到。
这是目前最隐蔽的方式,常用于游戏脚本或极高价值的抢购。
- 原理:
- 驱动级: 使用定制的鼠标驱动(如罗技驱动映射、DD 驱动、Interception 驱动),在内核层模拟信号。
- 物理级: 使用单片机(如 Arduino Pro Micro, Raspberry Pi),通过 USB 接口将自己伪装成一个真实的 HID 设备(鼠标/键盘)。
- 检测风险: 几乎为 0。浏览器和操作系统都认为这就是真实的物理硬件输入。
如果不考虑连续运动轨迹(即假设你只发了一个点击动作),单纯把 PyAutoGUI 产生的 JS 事件对象 和 Playwright 产生的 JS 事件对象 放在显微镜下对比:
答案是:它们并不完全一样。
虽然对于 99% 的普通网站检测逻辑(比如简单的 event.isTrusted 检查)来说,它们看起来是一样的,但在**高等级的反作弊系统(如 Akamai, Cloudflare, Datadome 的高级模式)**眼里,它们在“基因”层面存在微小的差异。
以下是具体的差异点:
- PyAutoGUI:
- 真实性: 它的
isTrusted: true是原生的。 - 原理: 浏览器内核通过 Windows 消息队列收到了真实的硬件中断信号(虽然是 OS 模拟的)。浏览器此时真心认为“这就是用户点的”,所以主动打上了
true标记。
- 真实性: 它的
- Playwright:
- 真实性: 它的
isTrusted: true是伪造的(或者说“强制”的)。 - 原理: Playwright 通过 CDP 协议命令浏览器:“生成一个事件,并且把
isTrusted设为true”。虽然结果也是true,但在浏览器内核的极深层(C++ 源码层面),这两种事件进入渲染流水线的路径是不一样的。 - 检测风险: 虽然 JS 层面很难读出区别,但如果反作弊脚本利用了某些浏览器 Bug 或者 渲染帧时序(Frame Timing) 的差异,是有可能推断出这个事件是“无中生有”插入的。
- 真实性: 它的
Playwright 生成的事件往往太“干净”或“完美”了,而 PyAutoGUI 继承了操作系统的“脏”数据。
- 精度问题:
- Playwright: 你告诉它点击
(100, 200),它生成的clientX/Y就是精确的100, 200。 - PyAutoGUI: 它依赖操作系统缩放(DPI Scaling)。如果你屏幕有缩放(比如 125%),你命令移动到 100,JS 实际收到的可能是
100.000002或者有微小偏差。这种**非整数的“噪音”**反而更像真实环境。
- Playwright: 你告诉它点击
- 多余属性 (Metadata):
- 真实的鼠标事件(PyAutoGUI)可能会携带一些与当前特定硬件驱动相关的边缘属性(比如某些游戏鼠标特有的高精度压力值,或者数位板的 Tilt 值)。
- Playwright 生成的事件通常只包含标准属性,缺乏这些“环境噪音”。
这是最高端的检测手段之一。
- PyAutoGUI:
- 事件触发是异步且混乱的。操作系统什么时候把消息给浏览器,浏览器就什么时候触发。它与浏览器的**渲染帧(Refresh Rate)**不完全同步。
- Playwright:
- CDP 命令通常由浏览器的主事件循环(Event Loop)处理。这意味着 Playwright 的输入事件往往会非常完美地对齐浏览器的渲染周期(例如总是正好在每一帧的开始或结束触发)。
- 检测点: 如果统计大量点击事件,发现它们的时间戳总是与 16.6ms(60Hz 刷新率)存在某种数学上的整除关系,那就是脚本特征。
这是最容易被忽略,但最容易导致露馅的地方。
- 场景: 假设你的浏览器窗口现在被另一个窗口遮挡了一半。
- PyAutoGUI:
- 它模拟的是“物理光标”。如果你让它点击一个被遮挡的坐标,它实际点击的是最上层遮挡它的那个窗口,而不是浏览器。
- 结果: 浏览器里根本收不到 JS 事件,或者收到一个
window.blur(失去焦点)事件。逻辑断裂。
- Playwright:
- 它模拟的是“虚拟事件”。即使浏览器被最小化,或者被遮挡,它依然能把点击事件精准地送达网页内的按钮上。
- 结果: 网页在不可见(Visiblity: Hidden)或者被遮挡的情况下,依然收到了点击事件。
- 检测判定: “非人哉”。人类不可能点击一个他看不见的按钮。