使用Python/Selenium(类似于pptr ghost-cursor)移动鼠标,与人类相似

xdnvmnnf  于 2023-04-04  发布在  Python
关注(0)|答案(1)|浏览(146)

bounty将在21小时后过期。回答此问题可获得+100声望奖励。Mévatlavé Kraspek希望引起更多关注此问题。

我尝试这个代码:Human-like mouse movements via Selenium但是试图弄清楚如何将其集成到真实的生活中的scraper来跟随我的鼠标圆顶DOM元素:

#!/usr/bin/python
# https://stackoverflow.com/questions/39422453/human-like-mouse-movements-via-selenium
import os
from time import sleep
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.action_chains import ActionChains
import numpy as np
import scipy.interpolate as si

#curve base
points = [[-6, 2], [-3, -2],[0, 0], [0, 2], [2, 3], [4, 0], [6, 3], [8, 5], [8, 8], [6, 8], [5, 9], [7, 2]];
points = np.array(points)
x = points[:,0]
y = points[:,1]

t = range(len(points))
ipl_t = np.linspace(0.0, len(points) - 1, 100)

x_tup = si.splrep(t, x, k=3)
y_tup = si.splrep(t, y, k=3)

x_list = list(x_tup)
xl = x.tolist()
x_list[1] = xl + [0.0, 0.0, 0.0, 0.0]

y_list = list(y_tup)
yl = y.tolist()
y_list[1] = yl + [0.0, 0.0, 0.0, 0.0]

x_i = si.splev(ipl_t, x_list)
y_i = si.splev(ipl_t, y_list)

url = "https://codepen.io/falldowngoboone/pen/PwzPYv"
driver = webdriver.Chrome()
driver.get(url)

action =  ActionChains(driver);

startElement = driver.find_element(By.ID, 'drawer')

# First, go to your start point or Element:
action.move_to_element(startElement);
action.perform();

# https://stackoverflow.com/a/70796266/465183
for mouse_x, mouse_y in zip(x_i, y_i):
    # Here you should reset the ActionChain and the 'jump' wont happen:
    action =  ActionChains(driver)
    action.move_by_offset(mouse_x,mouse_y);
    action.perform();
    print(mouse_x, mouse_y)

是否有类似NodeJS/pptr Ghost Cursor的Python模块来方便集成?
或者这里的任何人都可以向我们展示一种将其集成到真实的生活中的刮刀中的方法?

已创建功能请求:https://github.com/SeleniumHQ/selenium/issues/11824

slsn1g29

slsn1g291#

**一个

https://youtu.be/zZfPST2QS-g
我认为有一个更好的方法,像我在这里做的那样使用Bezier curves,像你的github链接建议的那样使用Selenium ActionsChains,重写类来做像driver.move_to_element()driver.random_mouse()这样的事情,但这对于简单的需求来说效果很好:

git clone https://github.com/sputnick-dev/pyautogui-with-selenium.git
cd pyautogui-with-selenium
./run

代码以避免仅链接回答:

paw文件:

#!/usr/bin/env python3
import random
import bezier
import pyautogui
import numpy as np
from time import sleep
from random import uniform as randfloat
from selenium.webdriver.common.by import By
from selenium.common.exceptions import TimeoutException
from selenium import webdriver

def slow_type(element, text: str):
    """Send a text to an element one character at a time with a delay."""
    for character in text:
        element.send_keys(character)
        sleep(randfloat(0.05,0.3))

def resting_mouse():
    """move mouse to right of screen."""

    panelWidht = driver.execute_script('return window.outerWidth;')
    start = pyautogui.position()
    end = random.randint(panelWidht-100, panelWidht), random.randint(400,850)

    x2 = (start[0] + end[0])/2 #midpoint x
    y2 = (start[1] + end[1]) / 2 ##midpoint y

    control1X = (start[0] + x2)/2
    control2X = (end[0] + x2) / 2

    # Two intermediate control points that may be adjusted to modify the curve.
    control1 = control1X, y2 ##combine midpoints to create perfect curve
    control2 = control2X, y2 ## using y2 for both to get a more linear curve

    # Format points to use with bezier
    control_points = np.array([start, control1, control2, end])
    points = np.array([control_points[:, 0], control_points[:, 1]])  # Split x and y coordinates
    # You can set the degree of the curve here, should be less than # of control points
    degree = 3
    # Create the bezier curve
    curve = bezier.Curve(points, degree)

    curve_steps = 70  # How many points the curve should be split into. Each is a separate pyautogui.moveTo() execution
    delay = 0.008  # Time between movements. 1/curve_steps = 1 second for entire curve

    # Move the mouse
    for j in range(1, curve_steps + 1):
        # The evaluate method takes a float from [0.0, 1.0] and returns the coordinates at that point in the curve
        # Another way of thinking about it is that i/steps gets the coordinates at (100*i/steps) percent into the curve
        x, y = curve.evaluate(j / curve_steps)
        pyautogui.moveTo(x, y)  # Move to point in curve
        pyautogui.sleep(delay)  # Wait delay
    sleep(2)

def bezier_mouse(location, size, panelHeight): ##move mouse to middle of element
    x, relY = location["x"], location["y"] ##abs X and relative Y
    absY = relY + panelHeight
    w, h = size["width"], size["height"]
    wCenter = w/2
    hCenter = h/2
    xCenter = int(wCenter + x)
    yCenter = int(hCenter + absY)

    start = pyautogui.position()
    end = xCenter, yCenter

    x2 = (start[0] + end[0]) / 2 #midpoint x
    y2 = (start[1] + end[1]) / 2 ##midpoint y

    control1X = (start[0] + x2) / 2
    control1Y = (end[1] + y2) / 2

    control2X = (end[0] + x2) / 2
    control2Y = (start[1] + y2) / 2

    # Two intermediate control points that may be adjusted to modify the curve.
    control1 = control1X, y2 ##combine midpoints to create perfect curve
    control2 = control2X, y2

    # Format points to use with bezier
    control_points = np.array([start, control1, control2, end])
    points = np.array([control_points[:, 0], control_points[:, 1]])  # Split x and y coordinates
    # You can set the degree of the curve here, should be less than # of control points
    degree = 3

    # Create the bezier curve
    curve = bezier.Curve(points, degree)

    curve_steps = 70  # How many points the curve should be split into. Each is a separate pyautogui.moveTo() execution
    delay = 0.008  # Time between movements. 1/curve_steps = 1 second for entire curve

    # Move the mouse
    for j in range(1, curve_steps + 1):
        # The evaluate method takes a float from [0.0, 1.0] and returns the coordinates at that point in the curve
        # Another way of thinking about it is that i/steps gets the coordinates at (100*i/steps) percent into the curve
        x, y = curve.evaluate(j / curve_steps)
        pyautogui.moveTo(x, y)  # Move to point in curve
        pyautogui.sleep(delay)  # Wait delay

# Disable pyautogui pauses
pyautogui.MINIMUM_DURATION = 0
pyautogui.MINIMUM_SLEEP = 0
pyautogui.PAUSE = 0
# avoid Exception when mouse if in a top corner
pyautogui.FAILSAFE = False

# instanciate Chrome websriver
driver = webdriver.Chrome()
driver.maximize_window()
driver.implicitly_wait(0.5)

try:
    driver.get("http://localhost:8000")
except TimeoutException:
    driver.execute_script("window.stop();")

sleep(2)
e1 = driver.find_element(By.ID, "change-me-paw")
e2 = driver.find_element(By.ID, "textarea")

panelHeight = driver.execute_script('return window.outerHeight - window.innerHeight;')

location1 = e1.location ## coords of element1
location2 = e2.location ## coords of element2
size1 = e1.size ## size of element1
size2 = e2.size ## size of element2
sleep(3)
bezier_mouse(location1, size1, panelHeight)
e1.click()
sleep(2)
bezier_mouse(location2, size2, panelHeight)
slow_type(e2, 'I type like a human being...')
sleep(2)
resting_mouse()
sleep(2)
driver.close()

其余的文物在仓库。

运行 Package 脚本:

#!/bin/bash

trap 'kill $pid $$' 1 2 3 15

[[ ! -e .req ]] && pip3 install -r requirements.txt && touch .req
cd tests/
python3 -m http.server &
pid=$!
cd ..
./paw
kill $pid &>/dev/null

相关问题