selenium 滚动元素到视图(中心)

问题描述 投票:0回答:5

当一个元素在 selenium 的视图之外并且尝试与其交互时,selenium 通常会先隐式地将元素滚动到视图中。这很棒,但令人烦恼的是它通常将元素放入视图中。我的意思是,如果元素位于窗口下方,它将向下滚动足够远,直到元素刚好与窗口边缘接壤。

通常这很好,但是当在有边框的网站上工作时,这会导致许多此类错误

Selenium::WebDriver::Error::UnknownError:
       unknown error: Element is not clickable at point (438, 747). Other element would receive the click: <body>...</body>

因为通常网页的边框位于其上方,但无论如何都会尝试单击该元素。有办法处理这个吗?也许在视野之外时自动将元素移动到屏幕中心?我正在考虑通过 ruby 进行猴子修补。

ruby selenium-webdriver watir-webdriver
5个回答
43
投票

这应该可以将元素滚动到视图中心:

WebElement element = driver.findElement(By.xxx("xxxx"));

String scrollElementIntoMiddle = "var viewPortHeight = Math.max(document.documentElement.clientHeight, window.innerHeight || 0);"
                                            + "var elementTop = arguments[0].getBoundingClientRect().top;"
                                            + "window.scrollBy(0, elementTop-(viewPortHeight/2));";

((JavascriptExecutor) driver).executeScript(scrollElementIntoMiddle, element);

3
投票

是的,可以自动滚动浏览器,以便我们与之交互的任何元素都位于窗口的中心。我下面有一个工作示例,使用 selenium-webdriver-2.41.0 和 Firefox 28 在 ruby 中编写和测试。

完全披露:您可能需要稍微编辑部分代码才能使其正常工作。 解释如下。 Selenium::WebDriver::Mouse.class_eval do # Since automatic centering of elements can be time-expensive, we disable # this behavior by default and allow it to be enabled as-needed. self.class_variable_set(:@@keep_elements_centered, false) def self.keep_elements_centered=(enable) self.class_variable_set(:@@keep_elements_centered, enable) end def self.keep_elements_centered self.class_variable_get(:@@keep_elements_centered) end # Uses javascript to attempt to scroll the desired element as close to the # center of the window as possible. Does nothing if the element is already # more-or-less centered. def scroll_to_center(element) element_scrolled_center_x = element.location_once_scrolled_into_view.x + element.size.width / 2 element_scrolled_center_y = element.location_once_scrolled_into_view.y + element.size.height / 2 window_pos = @bridge.getWindowPosition window_size = @bridge.getWindowSize window_center_x = window_pos[:x] + window_size[:width] / 2 window_center_y = window_pos[:y] + window_size[:height] / 2 scroll_x = element_scrolled_center_x - window_center_x scroll_y = element_scrolled_center_y - window_center_y return if scroll_x.abs < window_size[:width] / 4 && scroll_y.abs < window_size[:height] / 4 @bridge.executeScript("window.scrollBy(#{scroll_x}, #{scroll_y})", ""); sleep(0.5) end # Create a new reference to the existing function so we can re-use it. alias_method :base_move_to, :move_to # After Selenium does its own mouse motion and scrolling, do ours. def move_to(element, right_by = nil, down_by = nil) base_move_to(element, right_by, down_by) scroll_to_center(element) if self.class.keep_elements_centered end end

推荐用法:

在元素通常不在屏幕上的任何代码段的开头启用自动居中,然后禁用它。

注意:此代码似乎不适用于链式操作。示例:

driver.action.move_to(element).click.perform

滚动修复似乎没有更新 
click

位置。 在上面的示例中,它将单击元素的预滚动位置,从而产生误单击。


为什么

move_to



我选择了

move_to

,因为大多数基于鼠标的操作都会使用它,并且 Selenium 现有的“滚动到视图”行为发生在这一步中。这个特定的补丁不应该适用于任何在某种程度上不调用

move_to
的鼠标交互,我也不希望它适用于任何键盘交互,但理论上,如果你包装正确的方法,类似的方法应该有效功能。

为什么

sleep



我实际上不确定为什么在通过 

sleep

滚动后需要

executeScript
命令。通过我的特定设置,我可以删除
sleep
命令并且它仍然有效。来自网络上的
其他开发人员
类似示例包括延迟范围为 0.1 到 3 秒的 sleep 命令。作为一个疯狂的猜测,我想说这样做是出于交叉兼容性的原因。

如果我不想猴子补丁怎么办?

正如您所建议的,理想的解决方案是更改 Selenium 的“滚动到视图”行为,但我相信这种行为是由 selenium-webdriver gem 外部的代码控制的。 在线索变冷之前,我一路追踪代码到了

Bridge


对于不喜欢猴子补丁的人来说,

scroll_to_center

方法作为独立方法可以很好地工作,只需进行一些替换,其中

driver
是你的
Selenium::WebDriver::Driver
实例:

    driver.manage.window.position
  • 代替
    @bridge.getWindowPosition
  • driver.manage.window.size
  • 代替
    @bridge.getWindowSize
  • driver.execute_script
  • 代替
    @bridge.executeScript
    
        

1
投票

WebElement element = driver.findElement(By.id("id_of_element")); ((JavascriptExecutor) driver).executeScript("arguments[0].scrollIntoView(true);", element); Thread.sleep(500); //do anything you want with the element



0
投票

在 Java 中,这将是:

WebElement element = driver.findElement(By.id("tabs")).findElement(By.className("youarehere")); Point p = element.getLocation(); ((JavascriptExecutor) driver).executeScript("window.scroll(" + p.getX() + "," + (p.getY() + 200) + ");");



0
投票

driver.execute_script("arguments[0].scrollIntoView({ block: 'center' });", button)

	
© www.soinside.com 2019 - 2024. All rights reserved.