Sometimes when we try to find a WebElement from the HTML code by using the find
method of selenium, we might see a NoSuchElementException
or Unable to locate element
error on the terminal. But it is crystal clear from the HTML code that the element is present on that page. So, why does that happen? Today we will try to figure out one of the reasons behind that.
Why Wait Functions?
I tried to run the following code in my browser but several times came up with NoSuchElementException error. It may work out in your browser properly without any additional changes. But in my case, WebDriver was unable to click the “I Accept” button of the cookie policy hence failed to proceed further.
from selenium import webdriver driver = webdriver.Chrome(executable_path = r'G:/chromedriver_win32/chromedriver.exe') driver.maximize_window() driver.get('https://www.nba.com/players') cookies = driver.find_element_by_id("onetrust-accept-btn-handler") cookies.click()
When selenium is executing the script and clicking the button one after another, the browser requires a certain amount of time to process the request. But the script written with Python selenium does not know how much time it will take to find the button or sometimes it might not be able to find the desired button in a certain amount of time.
At that time, it will throw some kinds of script error or unexpected error because of the element that was not found at that moment or it was found after some time. In this situation, we need to wait for a certain amount of time allowing the browser to process our request properly and to execute the next line of code exactly when the earlier process is finished.
This happens because most of the web apps of recent age are built with Ajax. Ajax helps the browser to load more staff gradually. It keeps adding the elements even after the web driver finds the main page thus causing the time difference.
Python-Specific Wait or Hard Wait time.sleep()
To avoid the problem we can use python specific time.sleep()
function is also called hard wait where irrespective of the case the browser is loaded or not it will wait a specific amount of time. We just need to insert the time as an argument in the time.sleep()
function. We need to import the Python time
module for that. So, the code will look like this:
from selenium import webdriver import time driver = webdriver.Chrome(executable_path = r'G:/chromedriver_win32/chromedriver.exe') driver.maximize_window() driver.get('https://www.nba.com/players') time.sleep(10) cookies = driver.find_element_by_id("onetrust-accept-btn-handler") cookies.click()
Hopefully, the error will be fixed but the browser will wait exactly 10 seconds no matter how quickly it finds the element.
Implicit Wait
Sometimes your application might take 10 seconds to identify the element but you have been waiting for 6 seconds, in that case, you will not get the proper output in the terminal.
In the reverse case, you may set your hard wait to 20 seconds but you will get the response in 3 seconds. In that scenario even though your script finds the element in 3 seconds you have to wait for 20 seconds, the time you set as a hard wait. So, if we use this hard wait several times in a script, we will be delaying the execution and losing a great amount of time which is not a good practice. That is why selenium comes up with two features called implicit wait and explicit wait.
According to the documentation, In case of implicit wait when we are running the script the selenium will wait for the exact amount of time it takes to find the element. At the time the element is found, it will start executing the code without further delay.
from selenium import webdriver driver = webdriver.Chrome(executable_path = r'G:/chromedriver_win32/chromedriver.exe') driver.maximize_window() driver.get('https://www.nba.com/players') driver.implicitly_wait(20) cookies = driver.find_element_by_id("onetrust-accept-btn-handler") cookies.click()
Here, we set the implicitly wait for 20 seconds. what happens here, the driver wants to connect to the element every half a second. It keeps trying until it finds the element. Whenever it finds the element, it goes to the next line and starts executing the next line of code. Therefore, we do not need to wait for the extra amount of time as we do in case of a hard wait. if it does not find the element within the time frame of 20 seconds only then it will throw a βNoSuchElementException
β.
Explicit Wait
An explicit wait is when you define a condition on a WebDriver
and wait for that certain condition to occur before proceeding to the next step of the code. In explicit wait, we are doing two things at the same time. We are setting a certain time limit and at the same time, we are waiting for the occurrence of certain conditions. To use this method we need to import WebDriverWait
module from selenium.webdriver.support.ui
and expected_conditions
module from selenium.webdriver.support
.
from selenium import webdriver from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC driver = webdriver.Chrome(executable_path = r'G:/chromedriver_win32/chromedriver.exe') driver.maximize_window() driver.get('https://www.nba.com/players') cookies = WebDriverWait(driver,10).until(EC.presence_of_element_located(('id','onetrust-accept-btn-handler'))) cookies.click()
Here in the “cookies
” variable, we set the maximum time frame of 10 seconds, and βuntil
β is another function of WebDriverWait
which takes the condition statement as a parameter. By default, WebDriverWait
tries to connect to the element every 500 milliseconds and if there is no response in the allocated time, it throws a TimeoutException
.
Expected Conditions
As like βpresence_of_element_located
β, the condition we used in the βcookies
β variable, there are some common conditons that can be useful to automate the browser. Selenium API bindings make it easier with some available methods so that we do not need to to code an expected_condition
class repeatedly.
title_is
title_contains
presence_of_element_located
visibility_of_element_located
visibility_of
presence_of_all_elements_located
text_to_be_present_in_element
text_to_be_present_in_element_value
frame_to_be_available_and_switch_to_it
invisibility_of_element_located
element_to_be_clickable
staleness_of
element_to_be_selected
element_located_to_be_selected
element_selection_state_to_be
element_located_selection_state_to_be
alert_is_present
Which One is Best?
In Ajax-based web apps where the elements are already present on the web page but not yet visible due to its time-consuming page loading process, Explicit waits with a certain condition might be the best solution. It always works well in ajax driven complex web apps.
While In the case of explicit waits you need to use expected_conditions
every single time you require it, a single line of code written with implicit waits is good enough for the entire script. If you are not working with complex structured web pages then it is recommended to use implicit waits since you do not need to write the codes several times in a script.
Hope it was an enjoyable reading. Feel free to check out this link to learn more about selenium waits.
To improve your Python skills, check out our free email academy: