1

To click on an element which contains class and alt in selenium python.

A webpage contains certain folders with unique name, I want to click on folder by specifying their name or title. Below is the html tag, I tried many ways but I am ending up with errors.

<div class="folder">
<p>
<a alt="ABC" title="ABC">ABC</a>
</p>
</div>

Initially it used to work with below

driver.find_element_by_xpath("//a[@title='ABC']").click()    

I get "selenium.common.exceptions.NoSuchElementException: Message: no such element: Unable to locate element" error. Please help me solve this.

Tried below as well:

driver.find_element_by_xpath("//div[@class='folder']//a[@title='ABC']").click()

The above is also not working. Please request to guide me further.

Arpitha M
  • 85
  • 8
  • Does this answer your question? [selenium.common.exceptions.NoSuchElementException: Message: Unable to locate element:](https://stackoverflow.com/questions/27112731/selenium-common-exceptions-nosuchelementexception-message-unable-to-locate-ele) – charlie scott May 17 '21 at 09:58

2 Answers2

2

The first error could be caused by the driver attempting to find the elements before the page has properly loaded. This can be fixed by waiting until the page loads either manually with time.sleep or with the below code using WebDriverWait

from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
#10 is the no of seconds it will wait until it gives up on the page loading
element = WebDriverWait(driver, 10).until(
    EC.element_to_be_clickable((By.ID, "myDynamicElement"))
)

Code is from here: Python Selenium Webdriver selenium.common.exceptions.NoSuchElementException: Message: no such element: Unable to locate element

See here for more information: https://selenium-python.readthedocs.io/waits.html

charlie scott
  • 136
  • 1
  • 9
  • Your answer is good, voting for it. I'll just add more options. – vitaliis May 18 '21 at 01:00
  • Yes actually..i had to increase sleep for the page to be loaded. Thanks for the help. – Arpitha M May 18 '21 at 12:12
  • Thanks for the help..I increased sleep it worked :) – Arpitha M May 18 '21 at 12:14
  • I had one more question since I have many folders names as "ABC", "BCD", "EFG", is it possible to put a loop and read title name one after the other. I tried below: a_elements = driver.find_elements_by_class_name('folder') for i in a_elements: titles = driver.__getattribute__('title') print(titles) – Arpitha M May 18 '21 at 12:22
  • I'm not sure about `EC.element_to_be_clickable` but `driver.find_element(By.XPATH, [XPATH])` will return a list of all the elements found so you might be able to do that with implicit waits and `driver.find_element`. See [5.2 here](https://selenium-python.readthedocs.io/waits.html). This will change it for every call you make which may not be wanted. Maybe you could use `By.XPATH` with `EC.element_to_be_clickable` but I can't find anything about that online and haven't tested it so that may not be valid – charlie scott May 18 '21 at 16:24
1

First specify the locator to be as precise as possible, like //div[@class='folder']/p/a[@title='ABC'].

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


driver = webdriver.Firefox()

# Opening the page and other actions

wait = WebDriverWait(driver, 30)
wait.until(EC.element_to_be_clickable((By.XPATH, "//div[@class='folder']/p/a[@title='ABC']"))).click()

Also, you can do the same with css selector: .folder>p>a[title='ABC']

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


driver = webdriver.Firefox()

# Opening the page and other actions

wait = WebDriverWait(driver, 30)
wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, ".folder>p>a[title='ABC']"))).click()

Also, make sure that the locator is unique and is not inside iframe or a hidden DOM.

vitaliis
  • 4,082
  • 5
  • 18
  • 40