click through list elements with selenium python - python

The given list contains the references which will paste into the xpath ids (please find it below in my code) where x are the indexes of the elements.
I want to go through on all elements and click one by one by referring with its indexes, 'like so'
m_list = ['message0', 'message1', 'message2', 'message3', 'message4']
for x in range(0, len(m_list)):
WebDriverWait(driver, 10).until(EC.element_to_be_clickable(
(By.XPATH, f'//*[#id="{str(m_list[int(x)])}"]'))).click()
time.sleep(2)

This exception is common when you use Explicit wait which is WebDriverWait. This is expected since you wait for a fixed time for the element to be clickable. If the element was not found within that time, this exception is thrown. You might want to increase that time. The explicit wait can only be applied for specified elements, so if you are trying to click a paragraph, it won't work. If your elements appear after your initial click, that sleep command should also be in the loop, or you can use Implicit Wait.
Also if you want to iterate your list, you can use;
for i in m_list:
WebDriverWait(driver, 100).until(EC.element_to_be_clickable((By.XPATH, f'//*[#id="{i}"]'))).click()

Related

Python Selenium wait for an already-located WebElement to become clickable?

I have already viewed three StackOverflow solutions to almost this problem, but can't figure out how to apply it to an already-fetched web element.
Answer 1
Answer 2
Answer 3
Here is a sample of my current code:
def filter_shaded(tr_element):
td_list= tr_element.find_elements(By.CLASS_NAME, "row-major-td")
for td in td_list:
if 'row-major-td-shaded' not in td.get_attribute("class"):
return td
clickable_element = filter_shaded(...)
driver.implicitly_wait(3) # wait for element to be clickable
clickable_element.click() # here is the problem, sometimes getting ElementNotInteractableException
Essentially, I have a bunch of td elements inside of a table row. All but one of the elements is shaded. I use this function to "pick out" the unshaded element.
Now, I want to be able to click the unshaded tr element, but I have been having some issues with using a plain fixed delay such as driver.implicitly_wait(3). Sometimes the element is clickable long before 3 seconds and sometimes 3 seconds is not long enough for it to become clickable.
The only issue with the existing answers is that the code for locating the element is integrated into the wait code.
The solutions I posted above all suggest something along the lines of
element = WebDriverWait(driver, 20).until(
EC.element_to_be_clickable((By.ID, "my-id")))
element.click();
The above code locates an element by its ID and waits for it to become clickable. In my case, however, I have a custom function that filters out a single WebElement object and returns it (clickable_element in my original code). How can I tell Selenium to wait for an already-found WebElement to become clickable before clicking (and thereby avoiding any ElementNotInteractableExceptions)?
i.e.
def filter_shaded(tr_element):
td_list= tr_element.find_elements(By.CLASS_NAME, "row-major-td")
for td in td_list:
if 'row-major-td-shaded' not in td.get_attribute("class"):
return td
clickable_element = filter_shaded(...)
??? driver.wait_for_element_to_be_clickable(clickable_element) ??
clickable_element.click()
I'd rather not resort to hard coding or approximating a delay, since the elements can take anywhere from 0.5 to 11 seconds to become clickable and upping the wait time to 11s would be catastrophic for my runtime.

How to get all elements with a class within wait

I am scraping the xbox website with selenium but I encountered a problem when extracting someone's followers and friends: both elements have the same class, with no other property setting them apart, so I need to find all elements with that class and append them to a list and get the first, second value. I just need to know how to find all elements with a class whilst using wait until as seen below
followers = WebDriverWait(driver, 20).until(EC.visibility_of_element_located((By.CSS_SELECTOR, ".item-value-data"))).text
#this currently only gets the first element
I am aware of how to do this without wait; just putting elements, but I couldn't find anything regarding using this in wait.
WebDriverWait waits until at least 1 element matching the passed condition is found.
There is no expected condition supported by Selenium with Python to wait for predefined amount of elements matching or something like this.
What you can do is to put a small sleep after the wait to make the page fully loaded and then get the list of desired elements.
Like this:
WebDriverWait(driver, 20).until(EC.visibility_of_element_located((By.CSS_SELECTOR, ".item-value-data")))
time.sleep(1)
followers = []
followers_els = driver.find_elements_by_css_selector(".item-value-data")
for el in followers_els:
followers.append(el.text)

Python-Selenium - if else statement to check element visibility and clicking if available

I am using below code to check element visibility and click if available.
if element is available it is clicking quickly and moving to next code.
Problem:
if element is not visible/available it is taking more to time to skip and move to next code.
i understand it may take some time.
Question is:
is there any way to perform quickly if element not visible or if any other code to perform my test case quickly.
elements = self.driver.find_elements_by_partial_link_text("<element>")
if not elements:
print("Element Not Found")
else:
element = elements[0]
element.click()
based on your code, you are interested only on the first link (elements[0]), you can restrict the driver to find the first link only using below method
find_element_by_partial_link_text

How can I create a list of elements with the same xpath using selenium with python?

I need to click on several elements from the same table on the same webpage. I was thinking to do so with a for loop but in order to perform that action I first need to create a list of these elements.
//table[#border='1']//a
This is the xpath which selects all the elements from the table, how can I create a list of all these?
Use find_elements instead of find_element:
links = driver.find_elements_by_xpath("//table[#border='1']//a")
for values in links:
values.click()
While #SergiyKonoplyaniy answer was in the right direction, addressing your queries one by one:
How can I create a list of elements with the same xpath : To create a list of elements you need to use find_elements_by_xpath(xpath) which will create a List of elements matching the xpath you have specified.
Example:
my_links = driver.find_elements_by_xpath("//table[#border='1']//a")
Need to click on several elements: As you need to click() on several elements you have to iterate through all the elements you have captured in the List as follows:
for link in my_links:
link.click()
Now the most important aspect is, as per your xpath //table[#border='1']//a each and every element:
Has 3 distinct stages interms of presence, visibility and interactibility (i.e. clickability)
To collect the elements in a List you should always invoke a waiter with expected-conditions as visibility_of_all_elements_located(locator) as follows:
my_list = WebDriverWait(driver, 20).until(expected_conditions.visibility_of_all_elements_located((By.XPATH, "//table[#border='1']//a")))
The pseudo code as a solution for your question will be:
my_links = WebDriverWait(driver, 20).until(expected_conditions.visibility_of_all_elements_located((By.XPATH, "//table[#border='1']//a")))
for link in my_links:
link.click()
For your future reference, if you intend to invoke click() on any particular element always invoke a waiter with expected-conditions as element_to_be_clickable(locator) as follows:
WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, "desired_element_xpath"))).click()

WebDriverWait on find_elements_by_xpath

I am trying to figure out how WebDriverWait works with find_elements_by_xpath. How does it know that all related elements have loaded or does it just wait until page is loaded.
I can understand if we have a specific element using find_element_by_xpath, but not sure with find_elements_by_xpath.
For example:
elements = WebDriverWait(driver, 5).until(lambda driver: driver.find_elements_by_xpath("//table[#id='%s']/tbody/tr" % myid))
The expected condition you've presented would actually evaluate to True once there is at least one element matching the XPath expression. In other words, it is equivalent to:
expression = "//table[#id='%s']/tbody/tr" % myid
wait.until(EC.presence_of_element_located((By.XPATH, expression)))
webdriver isn't waiting for the page to be loaded -- it can't since the page's contents could be continually changing. Instead it simply executes the find_elements_* command and if successful, the WebDriverWait(...).until call returns the elements found. It is no different than find_element_by_xpath, except that more than one element may be returned.

Categories

Resources