Question: I try this code: Human-like mouse movements via Selenium but trying to figure out how to integrate it in a real life scraper to follow with my mouse with different DOM elements: #!/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)  Is there a Python module like NodeJS/pptr Ghost Cursor to facilitate integration? Or anybody here can show us a way to integrate it in a real life scraper? Created a feature request: https://github.com/SeleniumHQ/selenium/issues/11824

Answer: Using pyautogui+Selenium ChromeDriver https://youtu.be/zZfPST2QS-g I think there's a better way, using Bezier curves as I do here and Selenium ActionsChains like your github links suggest, overriding class to do something like driver.move_to_element() and driver.random_mouse(), but this is working well for simple requirements: git clone https://github.com/sputnick-dev/pyautogui-with-selenium.git cd pyautogui-with-selenium ./run  Code to avoid link only answer: paw file: #!/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()  The rest of artefacts are in repository. run wrapper script: #!/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