Skip to content

鼠标控制

鼠标API提供页面级别的完整鼠标输入控制,支持模拟逼真的光标移动、点击、双击和拖拽操作。当传入humanize=True时,鼠标操作使用人性化模拟:路径遵循自然贝塞尔曲线,配合菲茨定律时序、最小急动速度曲线、生理性手抖和过冲修正,使自动化操作几乎无法与人类行为区分。

集中式鼠标接口

所有鼠标操作均通过tab.mouse访问,为所有鼠标交互提供简洁统一的API。

快速开始

from pydoll.browser.chromium import Chrome
from pydoll.protocol.input.types import MouseButton

async with Chrome() as browser:
    tab = await browser.start()
    await tab.go_to('https://example.com')

    # 移动光标到指定位置
    await tab.mouse.move(500, 300)

    # 在指定位置点击
    await tab.mouse.click(500, 300)

    # 右键点击
    await tab.mouse.click(500, 300, button=MouseButton.RIGHT)

    # 双击
    await tab.mouse.double_click(500, 300)

    # 从一个位置拖拽到另一个位置
    await tab.mouse.drag(100, 200, 500, 400)

核心方法

move: 移动光标

将鼠标光标移动到页面上的指定位置:

# 默认移动(单个CDP事件,无模拟)
await tab.mouse.move(500, 300)

# 人性化移动(自然时序的曲线路径)
await tab.mouse.move(500, 300, humanize=True)

参数:

  • x:目标X坐标(CSS像素)
  • y:目标Y坐标(CSS像素)
  • humanize(仅关键字):模拟人类般的曲线移动(默认:False

click: 在指定位置点击

移动到指定位置并执行鼠标点击:

from pydoll.protocol.input.types import MouseButton

# 左键点击(默认,瞬时)
await tab.mouse.click(500, 300)

# 右键点击
await tab.mouse.click(500, 300, button=MouseButton.RIGHT)

# 通过click_count实现双击
await tab.mouse.click(500, 300, click_count=2)

# 人性化点击,自然移动
await tab.mouse.click(500, 300, humanize=True)

参数:

  • x:目标X坐标
  • y:目标Y坐标
  • button(仅关键字):鼠标按钮,可选 LEFTRIGHTMIDDLE(默认:LEFT
  • click_count(仅关键字):点击次数(默认:1
  • humanize(仅关键字):模拟人类般的行为(默认:False

double_click: 在指定位置双击

等价于click(x, y, click_count=2)的便捷方法:

await tab.mouse.double_click(500, 300)
await tab.mouse.double_click(500, 300, humanize=False)

down / up: 底层按钮控制

独立按下或释放鼠标按钮:

# 在当前位置按下左键
await tab.mouse.down()

# 释放左键
await tab.mouse.up()

# 右键
await tab.mouse.down(button=MouseButton.RIGHT)
await tab.mouse.up(button=MouseButton.RIGHT)

这些是底层原语,在当前光标位置操作,没有humanize参数。

drag: 拖放

按住鼠标按钮从起点移动到终点:

# 默认拖拽(瞬时)
await tab.mouse.drag(100, 200, 500, 400)

# 人性化拖拽,自然移动
await tab.mouse.drag(100, 200, 500, 400, humanize=True)

参数:

  • start_xstart_y:起始坐标
  • end_xend_y:结束坐标
  • humanize(仅关键字):模拟人类般的拖拽(默认:False

启用人性化

所有鼠标方法默认使用humanize=False。要启用带有自然贝塞尔曲线路径和真实时序的人性化模拟,传入humanize=True

# 人性化移动,菲茨定律时序的自然曲线路径
await tab.mouse.move(500, 300, humanize=True)

# 人性化点击:曲线移动+点击前停顿+按下+释放
await tab.mouse.click(500, 300, humanize=True)

# 人性化拖拽,自然曲线和停顿
await tab.mouse.drag(100, 200, 500, 400, humanize=True)

当规避检测很重要时推荐使用,例如与采用机器人检测的网站交互时。

人性化模式

当传入humanize=True时,鼠标模块应用多层逼真效果:

贝塞尔曲线路径

鼠标沿自然曲线轨迹移动,而非直线。控制点在起点→终点连线的垂直方向上随机偏移,采用非对称放置(移动初期曲率更大,模拟真实的弹道伸展)。

菲茨定律时序

移动持续时间遵循菲茨定律:MT = a + b × log₂(D/W + 1)。距离越远所需时间成比例增加,符合人类运动控制行为。

最小急动速度曲线

光标遵循钟形速度曲线,起始缓慢,中间加速到峰值速度,然后在末尾减速。这符合最平滑的人类运动轨迹。

生理性手抖

每帧添加小幅高斯噪声(σ ≈ 1像素),模拟手部震颤。颤抖幅度与速度成反比,光标缓慢或悬停时颤抖更多,快速弹道运动时颤抖减少。

过冲与修正

对于快速长距离移动(约70%概率),光标会超过目标3–12%的距离,然后做一个小的修正子运动回到目标。这符合真实人类运动控制数据。

点击前停顿

人性化点击包含点击前停顿(50–200毫秒),模拟按下按钮前的自然稳定时间。

自动人性化元素点击

当您使用element.click(humanize=True)时,鼠标API会从当前光标位置到元素中心产生逼真的贝塞尔曲线运动后再点击,使元素点击与人类行为无法区分。

# 默认点击:原始CDP按下/释放
button = await tab.find(id='submit')
await button.click()

# 带中心偏移
await button.click(x_offset=10, y_offset=5)

# 人性化点击:贝塞尔曲线运动+点击
await button.click(humanize=True)

位置追踪在元素点击之间保持。点击元素A,然后点击元素B,会产生从A到B的自然曲线路径。

自定义时序配置

所有人性化参数均可通过MouseTimingConfig配置:

from pydoll.interactions.mouse import MouseTimingConfig

config = MouseTimingConfig(
    fitts_a=0.070,              # 菲茨定律截距(秒)
    fitts_b=0.150,              # 菲茨定律斜率(秒/比特)
    frame_interval=0.012,       # mouseMoved事件间的基础间隔
    curvature_min=0.10,         # 最小路径曲率(距离的分数)
    curvature_max=0.30,         # 最大路径曲率
    tremor_amplitude=1.0,       # 颤抖sigma值(像素)
    overshoot_probability=0.70, # 快速移动时过冲的概率
    min_duration=0.08,          # 最小移动持续时间
    max_duration=2.5,           # 最大移动持续时间
)

# 应用到tab的鼠标实例
tab.mouse.timing = config

查看MouseTimingConfig数据类了解所有可用参数。

位置追踪

鼠标API在操作之间追踪光标位置:

# 初始位置为(0, 0)
await tab.mouse.move(100, 200)
# 位置现在是(100, 200)

await tab.mouse.click(300, 400)
# 位置现在是(300, 400)

# 底层方法使用追踪的位置
await tab.mouse.down()   # 在(300, 400)按下
await tab.mouse.up()     # 在(300, 400)释放

位置状态

鼠标位置在内部追踪。WebElement.click()在可用时自动使用tab.mouse,因此位置追踪在元素点击之间保持一致。

调试模式

启用调试模式以在页面上可视化鼠标移动。激活后,彩色点将绘制在透明覆盖画布上:

  • 蓝色点:移动过程中的光标路径
  • 红色点:点击位置
# 通过属性在运行时启用
tab.mouse.debug = True

# 现在所有移动都会绘制彩色点
await tab.mouse.click(500, 300)

# 完成后禁用
tab.mouse.debug = False

这对于调整时序参数和验证路径是否自然很有用。

实用示例

以逼真移动点击按钮

async def click_button_naturally(tab):
    # element.click() 自动使用 tab.mouse 进行人性化移动
    button = await tab.find(id='submit')
    await button.click()

拖动滑块

async def drag_slider(tab):
    slider = await tab.find(css_selector='.slider-handle')
    bounds = await slider.get_bounds_using_js()

    start_x = bounds['x'] + bounds['width'] / 2
    start_y = bounds['y'] + bounds['height'] / 2
    end_x = start_x + 200  # 向右拖拽200像素

    await tab.mouse.drag(start_x, start_y, end_x, start_y)

悬停在元素上

async def hover_menu(tab):
    menu = await tab.find(css_selector='.dropdown-trigger')
    bounds = await menu.get_bounds_using_js()

    await tab.mouse.move(
        bounds['x'] + bounds['width'] / 2,
        bounds['y'] + bounds['height'] / 2,
    )
    # 菜单现在应通过CSS :hover可见

了解更多