第11章 - 人类行为模拟
机器操作的最大特征是「太完美」——鼠标瞬间直线到达、打字零失误、间隔精确一致。这种机械的完美恰恰是风控系统识别「机器人」的依据。robotgo-flow 的人类行为模拟(Human Behavior Simulation)正是为了让自动化操作「像真人」,从而降低被检测的风险。本章深入其贝塞尔曲线鼠标轨迹、打字错误模拟、可变延时、滚动抖动与空闲行为的实现原理。
11.1 为什么要模拟人类
真实用户的操作充满「不完美」:
- 鼠标移动是带弧度的曲线,接近目标时会减速,甚至有轻微「过冲」再回调;
- 打字会偶尔打错,然后退格改正;
- 每次操作的间隔时间都不一样;
- 滚动是一段段的,不是匀速的;
- 等待时手会不自觉地微动。
机器如果把这些「不完美」也模拟出来,就更难与真人区分。这对需要对抗风控的自动化场景(如反爬、防机器人检测)很有价值。
11.2 如何启用
人类行为模拟通过 YAML 的 settings.human 启用:
settings:
human:
enabled: true # 启用
speed: 0.8 # 速度系数(0.1 ~ 5.0),越小越慢
mistake_rate: 0.03 # 打字错误率(0.0 ~ 1.0),0.03 = 3%
enabled:总开关,false(默认)时所有人类行为均不生效,走普通快速模式;speed:速度系数,范围 0.1~5.0,默认 1.0。数值越小操作越慢(越接近悠闲的真人),越大越快;mistake_rate:打字错误率,范围 0.0~1.0,默认 0.0(不出错)。0.03 表示约 3% 的字符会「打错再改」。
在源码中,引擎的 EnableHuman(enabled, speed, mistakeRate, idle, scroll, overshoot) 会据此创建 humanMode 实例;若未启用则该实例为 nil,引擎所有方法都走普通分支。
11.3 速度系数如何影响延时
humanMode 会根据 speed 推导出一系列延时范围(并做上下限裁剪):
- 打字延时:
typeDelayMin = clamp(50/speed, 10, 500)毫秒,typeDelayMax = clamp(250/speed, 30, 1000)毫秒; - 点击延时:
clickDelayMin = clamp(80/speed, 20, 600)毫秒,clickDelayMax = clamp(350/speed, 60, 1500)毫秒。
可以看出,speed 越小(比如 0.5),分母越小、延时越大,操作越慢;speed 越大,延时越小,操作越快。每次实际延时都在 [min, max] 之间随机取值,保证「不一致」。
11.4 贝塞尔曲线鼠标轨迹
这是人类模拟最直观的部分。普通模式下鼠标用 robotgo.MoveSmooth 走直线;人类模式下走三次贝塞尔曲线。
11.4.1 moveMouseTo 的逻辑
引擎移动鼠标时调用 moveMouseTo:
- 短距离(距离 < 20px):直接
robotgo.Move到位,加 10~40ms 随机延时(近距离没必要画曲线); - 长距离:生成一条贝塞尔曲线路径(
bezierPath)并沿路径逐点移动(walkPath); - 过冲(overshoot):15% 概率先「冲过头」±7px,再走回目标,模拟真人的手部惯性;
- 收尾:无论如何最后都执行一次精确的
robotgo.Move(x, y),确保最终落点准确。
11.4.2 bezierPath:路径生成
bezierPath 生成曲线的控制点:
- 两个控制点分别位于起终点距离的 20%~50% 处,并带有 ±45° 的角度偏移——这让每次的曲线形状都不同;
- 采样点数量为
clamp(int(dist * 0.8), 50, 200)——距离越长采样越多、轨迹越平滑。
11.4.3 walkPath:速度曲线
沿路径移动时,速度不是匀速的,而是模拟真人的「加速—巡航—减速—落点」:
| 进度区间 | 每点耗时 | 阶段 |
|---|---|---|
| 0~30% | 1~3 ms | 加速 |
| 30~70% | 2~5 ms | 巡航 |
| 70~90% | 5~12 ms | 减速 |
| 90~100% | 10~25 ms | 落点 |
越接近目标越慢,正是人手操作鼠标的典型节奏。
11.5 打字错误模拟
人类模式下,TypeText 逐字输入,并按 mistake_rate 概率制造「打错再改」的效果。当 rand.Float64() < mistakeRate 时,随机采用三种错误类型之一:
| 类型 | 行为 |
|---|---|
| 类型 0:相邻键错误 | 先按下相邻的错误键 → 退格 → 再按正确键 |
| 类型 1:漏字 | 先跳过当前字打下一个字 → 退格 → 补回当前字 → 再打下一个字(顺序修正) |
| 类型 2:顺序颠倒 | 先把两个字颠倒打出 → 连退两格 → 按正确顺序重打 |
其中「相邻键错误」依赖 keyboard_layout.go 中的 QWERTY 键盘邻接映射(adjacentKeys)——它记录了每个字母键在键盘上的相邻键,从而模拟「手指按偏了一个键」的真实错误。
每个字符之间还有 [typeDelayMin, typeDelayMax] 的随机间隔,让打字节奏自然。
11.6 滚动抖动
普通模式下 scroll 一次滚到位;人类模式下(启用滚动抖动 scrollJitter):
- 把滚动量拆成 1~3 单位的小步,逐步执行;
- 每步之间有 30~120ms 的随机间隔;
- 结束后有 20% 概率轻微反向回滚 1~2 单位——模拟真人「滚过头又拉回来一点」。
若滚动抖动未启用或滚动量很小(≤ 1),则直接调用 robotgo.ScrollDir 一次滚动。
11.7 空闲行为与鼠标微抖
真人在等待时,手不会完全静止。人类模式下的等待(idleWait)会:
- 把总等待时间拆成 200~500ms 的小块;
- 每一块有 15% 概率触发
idleWiggle——把鼠标微移 ±5px 再复位,模拟手的轻微抖动。
此外,步骤之间也有一定概率把鼠标移动到随机位置,进一步增加「人味」。
11.8 速度、错误率如何取值
参数的选择取决于你的目标:
- 追求隐蔽性:
speed取 0.5~0.9(偏慢更像真人),mistake_rate取 0.02~0.05(少量错误); - 追求效率:
speed取 1.5~3.0(更快),mistake_rate设 0(不出错); - 演示/调试:
speed取较小值让操作肉眼可见,便于观察每一步。
注意:错误率过高(如 > 0.1)会显著拖慢打字并可能引入意外,一般不建议;框架也会把 mistake_rate 裁剪到 [0.0, 1.0]、speed 裁剪到 [0.1, 5.0] 的合法范围。
11.9 完整示例
一个启用人类行为模拟、偏隐蔽的登录工作流片段:
name: "拟人登录"
settings:
element_timeout: 15
human:
enabled: true
speed: 0.7 # 偏慢,更像真人
mistake_rate: 0.03 # 3% 打字错误
inputs:
- name: user
label: "账号"
required: true
- name: pass
label: "密码"
required: true
mask: true
steps:
- name: "登录"
actions:
- open_url: "https://example.com/login"
- wait: "templates/form.png"
- type: {into: "templates/input_user.png", text: "$input.user"}
- type: {into: "templates/input_pass.png", text: "$input.pass"}
- click: "templates/btn_login.png"
- wait: "templates/home.png"
启用后,鼠标会以曲线移动、打字偶有修正、操作间隔不一,整体呈现「真人操作」的观感。
11.10 小结
本章我们深入了人类行为模拟这一核心机制:通过 settings.human 启用,speed 控制整体快慢并推导各类延时,mistake_rate 控制打字错误率。我们剖析了贝塞尔曲线鼠标轨迹(含过冲与加速—减速的速度曲线)、三种打字错误类型(相邻键/漏字/颠倒,依赖 QWERTY 邻接表)、滚动分块抖动与回滚、空闲时的鼠标微抖等实现细节,并给出了参数取值建议。这套机制让 robotgo-flow 的操作更贴近真人,降低被检测风险。下一章,我们回到工具层面,详解 CLI 的四个命令。