I'm trying to drive part of a web map akin to Google Maps, where zoom in/out is done by scrolling while moused over. Ideally, I'd like to be able to do something like this:
someElement.scroll(-50)
The closest methods I saw in the documentation were click
and send_keys
, but neither of those do scrolling. I've also tried sending scrolls to the page via Javascript, e.g. driver.execute_script("scroll(0,-50)")
This doesn't seem to do anything though.
How can I do this?
Hence, to scroll up or down with Selenium, a JavaScriptExecutor is a must. The scrollBy() method involves two parameters, x, and y, that represent the horizontal and vertical pixel values, respectively.
Selenium can execute JavaScript commands with the help of the executeScript method. To scroll down vertically in a page we have to use the JavaScript command window. scrollBy. Then pass the pixel values to be traversed along the x and y axis for horizontal and vertical scroll respectively.
Selenium cannot handle scrolling directly. It takes the help of the Javascript Executor to do scrolling action to a specific DIV. First of all we have to identify the specific DIV up to which we have to scroll to with the help of xpath or css locator.
To reproduce/test a mouse wheel, you'll have to emit the mouseover
, mousemove
and wheel
events to the top element with a script injection.
Here's a working example with Google Map:
from selenium import webdriver
from selenium.common.exceptions import WebDriverException
def wheel_element(element, deltaY = 120, offsetX = 0, offsetY = 0):
error = element._parent.execute_script("""
var element = arguments[0];
var deltaY = arguments[1];
var box = element.getBoundingClientRect();
var clientX = box.left + (arguments[2] || box.width / 2);
var clientY = box.top + (arguments[3] || box.height / 2);
var target = element.ownerDocument.elementFromPoint(clientX, clientY);
for (var e = target; e; e = e.parentElement) {
if (e === element) {
target.dispatchEvent(new MouseEvent('mouseover', {view: window, bubbles: true, cancelable: true, clientX: clientX, clientY: clientY}));
target.dispatchEvent(new MouseEvent('mousemove', {view: window, bubbles: true, cancelable: true, clientX: clientX, clientY: clientY}));
target.dispatchEvent(new WheelEvent('wheel', {view: window, bubbles: true, cancelable: true, clientX: clientX, clientY: clientY, deltaY: deltaY}));
return;
}
}
return "Element is not interactable";
""", element, deltaY, offsetX, offsetY)
if error:
raise WebDriverException(error)
options = webdriver.ChromeOptions()
options.add_argument("--disable-infobars --disable-extensions --window-size=1366,768")
driver = webdriver.Chrome(chrome_options=options)
driver.get("https://www.google.co.uk/maps")
# get element
elm = driver.find_element_by_css_selector("#scene > div.widget-scene > canvas")
# zoom in with mouse wheel
wheel_element(elm, -120)
# zoom out with mouse wheel
wheel_element(elm, 120)
As an alternative you could send the zoom shortucts which are +/- with Google map:
# get element
elm = driver.find_element_by_css_selector("#scene > div.widget-scene > canvas")
# zoom in with shortcut
elm.send_keys("+")
# zoom out with shortcut
elm.send_keys("-")
On google map, there is a zoom in/out button. You can use it instead of mouse scroll.
//To click on zoom in
driver.find_element_by_id('widget-zoom-in').click()
//To click on zoom out
driver.find_element_by_id('widget-zoom-out').click()
Florents great answer could be improved a tiny bit would by outsourcing the JS snippet into a separate file and wrap it into the old-style JS module format with readable parameter names.
A file called e.g. simulate_wheel.js
with:
/* global arguments */
(function (element, deltaY, offsetX, offsetY) {
var box = element.getBoundingClientRect();
var clientX = box.left + (offsetX || box.width / 2);
var clientY = box.top + (offsetY || box.height / 2);
var target = element.ownerDocument.elementFromPoint(clientX, clientY);
for (var e = target; e; e = e.parentElement) {
if (e === element) {
target.dispatchEvent(new MouseEvent("mouseover", {
view: window,
bubbles: true,
cancelable: true,
clientX: clientX,
clientY: clientY
}));
target.dispatchEvent(new MouseEvent("mousemove", {
view: window,
bubbles: true,
cancelable: true,
clientX: clientX,
clientY: clientY
}));
target.dispatchEvent(new WheelEvent("wheel", {
view: window,
bubbles: true,
cancelable: true,
clientX: clientX,
clientY: clientY,
deltaY: deltaY
}));
return "";
}
}
return "Element is not interactable";
}).apply(null, arguments);
Which then can be read and used the following
# Load it using the module loader, the module in this example is called "helper_js"
# Alternatively, simple read functions could be used
import pkgutil
wheel_js = pkgutil.get_data("helper_js", "simulate_wheel.js").decode("utf8")
def simulate_wheel(element, deltaY=120, offsetX=0, offsetY=0):
error = element._parent.execute_script(wheel_js, element, deltaY, offsetX, offsetY)
if error:
raise WebDriverException(error)
This is similar to how it's down inside the Selenium bindings for Python.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With