chromedriver 版本 >74 的 MoveTargetOutOfBoundsException 问题

MoveTargetOutOfBoundsException problem with chromedriver version >74

我不知道为什么 ActionChains move_to_element() 不能与 chromedriver >74 一起使用。

(但它适用于 chromedriver 74 和 geckodriver。)

虽然我在ActionChains前面加了这三行,还是移动到element上失败。

WebDriverWait(driver, 60).until(EC.presence_of_element_located((By.XPATH, xxxxx)))
WebDriverWait(driver, 60).until(EC.visibility_of_element_located((By.XPATH, xxxxx))
drvier.execute_script("arguments[0].scrollIntoView();", element)

ActionChains(driver).move_to_element(element).click().perform()

并抛出如下错误:

selenium.common.exceptions.MoveTargetOutOfBoundsException: Message: move target out of bounds (Session info: chrome=79.0.3945.117)

我也尝试使用 中提到的 move_to_element_with_offset,它仍然不起作用:

ActionChains(driver).move_to_element_with_offset(element, 5, 5).click().perform()

以下是我对 chromedriver 的设置。 是否对 ActionChains 有任何设置影响?

options = webdriver.ChromeOptions()
options.add_argument('--no-sandbox')
options.add_argument('log-level=3')
options.add_argument('--disable-dev-shm-usage')
options.add_argument('--no-proxy-server')
options.add_argument('--disable-extensions')
options.add_argument('--disable-infobars')
options.add_experimental_option("excludeSwitches", ["enable-automation"])
options.add_experimental_option('useAutomationExtension', False)
driver = webdriver.Chrome(executable_path=chromedriver_path, chrome_options=options)

由于您的用途是通过 ActionChains 调用 click() 而不是 presence_of_element_located()visibility_of_element_located() 您需要使用 expected_conditionselement_to_be_clickable()如下:

  • ActionChains的用法:

    ActionChains(driver).move_to_element(WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.CSS_SELECTOR, "element_css")))).click().perform()
    
  • 如果你必须在调用 click() 之前 scrollIntoView() 你需要为 visibility_of_element_located() 引入 WebDriverWait 并且你可以使用以下 :

    WebDriverWait(driver, 20).until(EC.visibility_of_element_located((By.XPATH, xxxxx))
    drvier.execute_script("arguments[0].scrollIntoView();", WebDriverWait(driver, 20).until(EC.visibility_of_element_located((By.XPATH, xxxxx)))
    ActionChains(driver).move_to_element(WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.CSS_SELECTOR, "element_css")))).click().perform()
    
  • 注意:您必须添加以下导入:

    from selenium.webdriver.support.ui import WebDriverWait
    from selenium.webdriver.common.by import By
    from selenium.webdriver.support import expected_conditions as EC
    

其他注意事项

确保:

  • Selenium 已升级到当前级别 Version 3.141.59
  • Chrome驱动程序 已更新为当前 ChromeDriver v79.0.3945.36 级别。
  • Chrome 已更新至当前 Chrome 版本 79.0 级别。 (根据 ChromeDriver v79.0 release notes
  • 清理你的项目工作区通过你的IDE重建你的项目只需要依赖。
  • 如果您的基础 Web Client 版本太旧,则通过 Revo Uninstaller 卸载它并安装最新的 GA 和发布版本的 Web Client .
  • 系统重启
  • 非 root 用户身份执行您的 @Test
  • 始终在 tearDown(){} 方法中调用 driver.quit() 以优雅地关闭和销毁 WebDriverWeb Client 实例.

更新

根据您的评论:

options.add_experimental_option('w3c', False)

为您工作,但根据 ChromeDriver 75.0.3770.8发行说明

Resolved issue 2536: Make standards mode (goog:chromeOptions.w3c:true) the default [Pri-2]

ChromeDriver 75.0 解决了这个问题。

所以最重要的是,chromeOptions.w3c需要默认设置为true。关闭 chromedriver 中的 w3c 来解决错误将违反最佳实践。我们在以下讨论中对此进行了详细讨论:

  • Cannot call non W3C standard command while in W3C mode (Selenium::WebDriver::Error::UnknownCommandError) with Selenium ChromeDriver in Cucumber Ruby

move_to_element 内部使用 move_to

def move_to_element(self, to_element):
    if self._driver.w3c: # default in chromedriver 79
        self.w3c_actions.pointer_action.move_to(to_element)

def move_to(self, element, x=None, y=None):
    #...
    el_rect = element.rect
    left_offset = el_rect['width'] / 2
    top_offset = el_rect['height'] / 2
    left = -left_offset + (x or 0)
    top = -top_offset + (y or 0)

    self.source.create_pointer_move(origin=element, x=int(left), y=int(top))

鼠标指针根据元素位置移动偏移量。您正在定位元素,然后使用 JavaScript 将其滚动到视图中,因此偏移量是通过错误的坐标计算的。

删除 JavaScript 卷轴应该可以解决问题。