115

I have a Selenium script (Python) that clicks a reply button to make the class anonemail appear. The time it takes for the class anonemail to appear varies. Because of that I have to use sleep until the element has appeared.

I want to wait until the class has appeared instead of using sleep. I have heard about wait commands, but I don't know how to use them.

This is what I have thus far:

browser.find_element_by_css_selector(".reply-button").click()
sleep(5)
email=browser.find_element_by_css_selector(".anonemail").get_attribute("value")
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Benjamin Arvola
  • 1,265
  • 2
  • 6
  • 6

6 Answers6

158

As per the best practices:

  • If your use case is to validate the presence of any element, you need to induce WebDriverWait setting the expected_conditions as presence_of_element_located() which is the expectation for checking that an element is present on the DOM of a page. This does not necessarily mean that the element is visible. So the effective line of code will be:

    WebDriverWait(browser, 20).until(EC.presence_of_element_located((By.CSS_SELECTOR, ".reply-button"))).click()
    
  • If your use case is to extract any attribute of any element you need to induce WebDriverWait setting the expected_conditions as visibility_of_element_located(locator) which is an expectation for checking that an element is present on the DOM of a page and visible. Visibility means that the element is not only displayed, but it also has a height and width that is greater than 0. So in your use case, effectively the line of code will be:

    email = WebDriverWait(driver, 20).until(EC.visibility_of_element_located((By.CSS_SELECTOR, "element_css"))).get_attribute("value")
    
  • If your use case is to invoke click() on any element you need to induce WebDriverWait setting the expected_conditions as element_to_be_clickable() which is an expectation for checking an element is visible and enabled such that you can click it. So in your use case, effectively the line of code will be:

    WebDriverWait(browser, 20).until(EC.element_to_be_clickable((By.CSS_SELECTOR, ".reply-button"))).click()
    

References

You can find a couple of detailed discussion in:

undetected Selenium
  • 183,867
  • 41
  • 278
  • 352
  • Thanks a lot! This doesn't show element not found error. However, it immediately closes the browser window even if an explicit wait exists. Do you know why? – Esraa Abdelmaksoud Mar 11 '23 at 20:19
53

After clicking the Reply button, use .visibility_of_element_located like below:

browser.find_element_by_css_selector(".reply-button").click()

# Wait for initialize, in seconds
wait = WebDriverWait(browser, 10)

email = wait.until(EC.visibility_of_element_located((By.CSS_SELECTOR, '.anonemail'))).get_attribute("value")
print(email)

Following import:

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

Waits documentation

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
frianH
  • 7,295
  • 6
  • 20
  • 45
16

You can use waits. Check for more information in Selenium waits.

In the example below we are waiting 10 seconds for the element to be visible, using the function visibility_of_element_located.

driver = webdriver.Firefox()
driver.get("http://somedomain/url_that_delays_loading")
try:
    element = WebDriverWait(driver, 10).until(
        EC.visibility_of_element_located((By.ID, "myDynamicElement"))
    )
finally:
    driver.quit()
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
daniboy000
  • 1,069
  • 2
  • 16
  • 26
9
  • WebDriverWait(driver, 5).until( EC.presence_of_element_located((By.CSS_SELECTOR, ".reply-button"))):

    • Hey driver, wait (0-5 seconds), when you see .reply-button is presence, return that button to me!
      • presence is present on the DOM. Hidden element is good enough.
  • WebDriverWait(driver, 5).until( EC.visibility_of_element_located((By.CSS_SELECTOR, ".reply-button”)))):

    • Hey driver, wait (0-5 seconds), when you see .reply-button is visibility, return that button to me!
      • visibility is present and visible on the DOM. Hidden element is not good enough!
  • WebDriverWait(driver, 5).until( EC.element_to_be_clickable((By.CSS_SELECTOR, ".reply-button”)))):

    • Hey driver, wait (0-5 seconds), when you see .reply-button is clickable, return that button to me!
      • clickable is present and visible and clickable on the DOM. Hidden element or non-clickable is not good enough!

Other available conditions

HoangYell
  • 4,100
  • 37
  • 31
  • 1
    I really like finding this kind of answers in SO: I think they help you learn fishing instead of only giving you a fish. Kudos! – PavoDive Apr 11 '23 at 20:35
8

You can use implicitly_wait:

from selenium import webdriver

driver = webdriver.Firefox()
driver.implicitly_wait(15)
driver.get("http://url")
driver.find_element_by_id("id_of_element").click()

It waits until element is loaded.

In your case the implementation would be,

browser.implicitly_wait(10)
browser.find_element_by_css_selector(".reply-button").click()
email = browser.find_element_by_css_selector(".anonemail").get_attribute("value")
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Mert Köklü
  • 2,183
  • 2
  • 16
  • 20
1

I also had a similar problem to yours. I tried using implicit_wait() and WebDriverWait, but they did not work.

So I solved setting the implicit_wait(10) in the web driver instance and using this snippet to click on the button:

element = driver.find_elements_by_xpath("//button[contains(string(), 'Log In')]")[0]
driver.execute_script("arguments[0].click();", element)
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
badr
  • 94
  • 1
  • 5