如何用Python实现基于WindMouse算法的类人鼠标移动?
实现遵循WindMouse算法的逼真鼠标移动
我不确定当前问题表述是否准确,想咨询是否可通过pyautogui、Selenium Actions或其他工具,让Python控制的所有鼠标移动都遵循WindMouse算法?我希望为自制机器人实现尽可能逼真的鼠标移动,若可行该如何操作?
核心结论
完全可以实现。WindMouse算法的核心是生成模拟人类行为的鼠标路径点,只需将不同工具的鼠标移动函数作为回调传入WindMouse的move_mouse参数即可。以下是针对不同工具的具体实现方案:
1. 使用PyAutoGUI实现
PyAutoGUI适合桌面级鼠标控制,只需将其moveTo函数作为回调传入WindMouse,分步执行路径点移动:
首先安装依赖:
pip install pyautogui numpy
实现代码:
import numpy as np import pyautogui import time sqrt3 = np.sqrt(3) sqrt5 = np.sqrt(5) def wind_mouse(start_x, start_y, dest_x, dest_y, G_0=9, W_0=3, M_0=15, D_0=12, move_mouse=lambda x,y: None): current_x,current_y = start_x,start_y v_x = v_y = W_x = W_y = 0 while (dist:=np.hypot(dest_x-start_x,dest_y-start_y)) >= 1: W_mag = min(W_0, dist) if dist >= D_0: W_x = W_x/sqrt3 + (2*np.random.random()-1)*W_mag/sqrt5 W_y = W_y/sqrt3 + (2*np.random.random()-1)*W_mag/sqrt5 else: W_x /= sqrt3 W_y /= sqrt3 if M_0 < 3: M_0 = np.random.random()*3 + 3 else: M_0 /= sqrt5 v_x += W_x + G_0*(dest_x-start_x)/dist v_y += W_y + G_0*(dest_y-start_y)/dist v_mag = np.hypot(v_x, v_y) if v_mag > M_0: v_clip = M_0/2 + np.random.random()*M_0/2 v_x = (v_x/v_mag) * v_clip v_y = (v_y/v_mag) * v_clip start_x += v_x start_y += v_y move_x = int(np.round(start_x)) move_y = int(np.round(start_y)) if current_x != move_x or current_y != move_y: move_mouse(current_x:=move_x,current_y:=move_y) time.sleep(0.01) # 模拟人类移动间隔 return current_x,current_y # 封装成PyAutoGUI调用函数 def pyautogui_wind_move(to_x, to_y): start_x, start_y = pyautogui.position() wind_mouse(start_x, start_y, to_x, to_y, move_mouse=pyautogui.moveTo) # 示例:移动到屏幕(500,500)位置 pyautogui_wind_move(500, 500)
2. 使用Selenium Actions实现
Selenium用于浏览器内的鼠标控制,需将WindMouse生成的路径转为相对位移,通过move_by_offset执行:
首先安装依赖:
pip install selenium numpy
实现代码:
import numpy as np import time from selenium import webdriver from selenium.webdriver.common.action_chains import ActionChains sqrt3 = np.sqrt(3) sqrt5 = np.sqrt(5) def wind_mouse(start_x, start_y, dest_x, dest_y, G_0=9, W_0=3, M_0=15, D_0=12, move_mouse=lambda dx,dy: None): current_x,current_y = start_x,start_y v_x = v_y = W_x = W_y = 0 while (dist:=np.hypot(dest_x-start_x,dest_y-start_y)) >= 1: W_mag = min(W_0, dist) if dist >= D_0: W_x = W_x/sqrt3 + (2*np.random.random()-1)*W_mag/sqrt5 W_y = W_y/sqrt3 + (2*np.random.random()-1)*W_mag/sqrt5 else: W_x /= sqrt3 W_y /= sqrt3 if M_0 < 3: M_0 = np.random.random()*3 + 3 else: M_0 /= sqrt5 v_x += W_x + G_0*(dest_x-start_x)/dist v_y += W_y + G_0*(dest_y-start_y)/dist v_mag = np.hypot(v_x, v_y) if v_mag > M_0: v_clip = M_0/2 + np.random.random()*M_0/2 v_x = (v_x/v_mag) * v_clip v_y = (v_y/v_mag) * v_clip start_x += v_x start_y += v_y move_x = int(np.round(start_x)) move_y = int(np.round(start_y)) if current_x != move_x or current_y != move_y: dx = move_x - current_x dy = move_y - current_y move_mouse(dx, dy) current_x, current_y = move_x, move_y time.sleep(0.01) return current_x,current_y # 封装成Selenium调用函数 def selenium_wind_move(driver, to_x, to_y): action = ActionChains(driver) action.move_by_offset(0,0).perform() # 重置坐标原点为当前鼠标位置 start_x, start_y = 0, 0 def selenium_move(dx, dy): action.move_by_offset(dx, dy).perform() wind_mouse(start_x, start_y, to_x, to_y, move_mouse=selenium_move) # 示例用法 driver = webdriver.Chrome() driver.get("https://example.com") # 移动到页面视口内(300, 200)位置 selenium_wind_move(driver, 300, 200)
3. 使用pynput实现
pynput支持系统级鼠标控制,适合更底层的桌面自动化场景:
首先安装依赖:
pip install pynput numpy
实现代码:
import numpy as np import time from pynput.mouse import Controller sqrt3 = np.sqrt(3) sqrt5 = np.sqrt(5) def wind_mouse(start_x, start_y, dest_x, dest_y, G_0=9, W_0=3, M_0=15, D_0=12, move_mouse=lambda x,y: None): current_x,current_y = start_x,start_y v_x = v_y = W_x = W_y = 0 while (dist:=np.hypot(dest_x-start_x,dest_y-start_y)) >= 1: W_mag = min(W_0, dist) if dist >= D_0: W_x = W_x/sqrt3 + (2*np.random.random()-1)*W_mag/sqrt5 W_y = W_y/sqrt3 + (2*np.random.random()-1)*W_mag/sqrt5 else: W_x /= sqrt3 W_y /= sqrt3 if M_0 < 3: M_0 = np.random.random()*3 + 3 else: M_0 /= sqrt5 v_x += W_x + G_0*(dest_x-start_x)/dist v_y += W_y + G_0*(dest_y-start_y)/dist v_mag = np.hypot(v_x, v_y) if v_mag > M_0: v_clip = M_0/2 + np.random.random()*M_0/2 v_x = (v_x/v_mag) * v_clip v_y = (v_y/v_mag) * v_clip start_x += v_x start_y += v_y move_x = int(np.round(start_x)) move_y = int(np.round(start_y)) if current_x != move_x or current_y != move_y: move_mouse(current_x:=move_x,current_y:=move_y) time.sleep(0.01) return current_x,current_y # 封装成pynput调用函数 def pynput_wind_move(to_x, to_y): mouse = Controller() start_x, start_y = mouse.position wind_mouse(start_x, start_y, to_x, to_y, move_mouse=lambda x,y: setattr(mouse, 'position', (x,y))) # 示例:移动到屏幕(600, 400)位置 pynput_wind_move(600, 400)
优化提示
- 调整WindMouse的参数(
G_0、W_0等)可以改变移动风格:增大W_0会让路径更随机,减小则更平滑;调整M_0可以控制最大移动步长。 - 增加的
time.sleep(0.01)是模拟人类鼠标移动的间隔,可根据需求微调时长。
内容的提问来源于stack exchange,提问作者heyitme
相关产品推荐
相关产品推荐

