简体   繁体   English

selenium 中的隐式或显式等待在 time.sleep 之前不能可靠地工作吗?

[英]implicit or explicit waits in selenium don't work reliably by time.sleep does?

I have some selenium code to log in to jupyterlab (running locally).我有一些 selenium 代码可以登录到 jupyterlab(在本地运行)。 Without waits, it fails as it tries to find the password input textbox before it exists.没有等待,它会失败,因为它会尝试在密码输入文本框存在之前找到它。 So I tried to use an explicit wait as that seems like the cleanest solution, but it works erratically.所以我尝试使用显式等待,因为这似乎是最干净的解决方案,但它工作不规律。 Implicit waits never work, it seems to block the webserver for 10 seconds before loading the page so always fails.隐式等待永远不会起作用,它似乎会在加载页面之前阻止网络服务器 10 秒,所以总是失败。 time.sleep always works, however it loads the page and then waits the 10 seconds before entering the password which is inefficient and less clean than the selenium wait methods which as I understand wait up to 10 seconds but stop waiting as soon as the element becomes available. time.sleep始终有效,但是它会加载页面,然后在输入密码之前等待 10 秒,这比 selenium 等待方法效率低且不干净,据我所知,等待方法最多等待 10 秒,但一旦元素变为可用的。 What have I done wrong?我做错了什么?

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support import expected_conditions as ec
from selenium.webdriver.support.wait import WebDriverWait
  1. Explicit wait - sometimes works显式等待 - 有时有效

    driver = webdriver.Firefox() driver.get(f"http://localhost:8888") wait = WebDriverWait(driver, 10) password_input = wait.until(ec.presence_of_element_located((By.ID, "password_input"))) password = "my_password" password_input.send_keys(password + Keys.RETURN)

    sometimes I get the error:有时我会收到错误:

    selenium.common.exceptions.ElementNotInteractableException: Message: Element is not reachable by keyboard selenium.common.exceptions.ElementNotInteractableException:消息:键盘无法访问元素

  2. Implicit wait - sometime errors隐式等待 - 有时会出错

    driver = webdriver.Firefox() driver.get(f"http://localhost:8888") driver.implicitly_wait(10) password_input = driver.find_element_by_css_selector("password_input") password = "my_password" password_input.send_keys(password + Keys.RETURN)

    sometimes I get the error:有时我会收到错误:

    selenium.common.exceptions.ElementNotInteractableException: Message: Element is not reachable by keyboard selenium.common.exceptions.ElementNotInteractableException:消息:键盘无法访问元素

  3. time.sleep - always works time.sleep - 总是有效

    driver = webdriver.Firefox() driver.get(f"http://localhost:8888") time.sleep(10) password_input = driver.find_element_by_id("password_input") password = "my_password" password_input.send_keys(password + Keys.RETURN)

    While this always works, it wastes time for no reason.虽然这总是有效的,但它会无缘无故地浪费时间。 And the selenium wait method really should work.并且 selenium 等待方法确实应该有效。

What am I doing wrong?我究竟做错了什么?

While How to resolve ElementNotInteractableException: Element is not visible in Selenium webdriver?虽然如何解决 ElementNotInteractableException:元素在 Selenium webdriver 中不可见? is technically a duplicate, it solves this for Java, and it always annoys me when a duplicate is for a different language, so I'll write this answer for Python.从技术上讲,它是重复的,它为 Java 解决了这个问题,当重复用于不同的语言时它总是让我烦恼,所以我将为 Python 写这个答案。


The ec.presence_of_element_located(...) method just tests for the presence of an element within the document object model. ec.presence_of_element_located(...)方法仅测试文档 object model 中是否存在元素。 It does not ensure that element is something the user can interact with.它不能确保元素是用户可以与之交互的东西。 Another element might overlap it, or the element might be hidden from view for a brief moment before you call password_input.send_keys(...) .另一个元素可能会与它重叠,或者在您调用password_input.send_keys(...)之前,该元素可能会暂时隐藏在视图之外。

Waiting until the element is "clickable" is usually the best solution:等到元素“可点击”通常是最好的解决方案:

driver = webdriver.Firefox()
driver.get(f"http://localhost:8888")
wait = WebDriverWait(driver, 10)

# waiting until element is "clickable" means user can interact with
# it, and thus send_keys(...) can simulate keyboard interaction.
password_input = wait.until(ec.element_to_be_clickable((By.ID, "password_input")))

password = "my_password"
password_input.send_keys(password + Keys.RETURN)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM