Castle
Castle

Reputation: 411

Selenium - how to reliably click on text?

I am trying to click on text links and that does not work:

from selenium import webdriver
driver = webdriver.Firefox()
driver.get("https://my.gumtree.com/login")
driver.find_element_by_name("username").send_keys(email)
driver.find_element_by_id("existingUser").click()
driver.find_element_by_id("fld-password").send_keys(password)
driver.find_element_by_xpath("//*[contains(text(), 'Continue')]").click() # works

driver.get("https://my.gumtree.com/postad")
driver.find_elements_by_xpath("//*[text()='For Sale']")[-1].click() # this now works, thanks
# driver.find_element_by_xpath("//*[contains(@span,'Appliances']").click() # this worked but I need the next line instead
driver.find_element_by_xpath("//span[text()[normalize-space()='Phones, Mobile Phones & Telecoms']]").click() # this does not work
driver.find_element_by_xpath("//span[text()[normalize-space()='Phones, Mobile Phones & Telecoms']]").click() # this does not work either
driver.find_element_by_xpath("//span[text()[normalize-space()='Mobile Phones']]").click()
driver.find_element_by_xpath("//span[text()[normalize-space()='Other']]").click()

HTML:

<li class="border-b is-parent" data-category-name="Appliances" data-category-url="kitchen-appliances" data-category-id="2485" data-category-children="true">
  <span class="category-name">
    <span class="category-list-control is-parent">
    </span>
    Appliances
  </span>
</li>

What do I do wrong?

Upvotes: 1

Views: 12468

Answers (6)

murali selenium
murali selenium

Reputation: 3927

As per provided HTML code I hope it will work:

 //span[contains(text(),'For Sale')] 

Upvotes: 2

sowa
sowa

Reputation: 1329

Your provided HTML does not show that the Appliances span contains a lot of whitespace which is likely the reason you are not finding this element. Try the following Xpath to find the Appliances span,

//span[text()[normalize-space()='Appliances']]

Below is the script I used,

from selenium import webdriver

email, password = 'your-own-email', 'your-own-password'
driver = webdriver.Firefox()
driver.implicitly_wait(10)

driver.get("https://my.gumtree.com/login")
driver.find_element_by_name("username").send_keys(email)
driver.find_element_by_id("existingUser").click()
driver.find_element_by_id("fld-password").send_keys(password)
driver.find_element_by_xpath("//*[contains(text(), 'Continue')]").click()

driver.get("https://my.gumtree.com/postad")
driver.find_elements_by_xpath("//*[text()='For Sale']")[-1].click()
driver.find_element_by_xpath("//span[text()[normalize-space()='Appliances']]").click()
driver.find_element_by_xpath("//span[text()[normalize-space()='Home Appliances']]").click()
driver.find_element_by_xpath("//span[text()[normalize-space()='Other Home Appliances']]").click()

For those elements that are not in view use the approach below,

element = driver.find_element_by_xpath("//span[text()[normalize-space()='Phones, Mobile Phones & Telecoms']]")
driver.execute_script("return arguments[0].scrollIntoView();", element)
element.click()

Upvotes: 0

Striter Alfa
Striter Alfa

Reputation: 1577

This kind of contains in XPath can be used in advanced scenarios, like your:

//span[text()[contains(.,'Appliances')]]

@Edit:

You can test all the XPath responses in this topic in Google Chrome using $x("selector"). Maybe the problem is in your selenium version.

I really don't know the python syntax (I used to create tests in C#), but you can do a ugly code that will work. Try to change the code to python, I think there are some errors:

elements = driver.find_elements_by_cssselector("span.category-name")

for element in elements:
    if (element.text == "Appliances" || element.text == "Home Appliances" || element.text == "Other Home Appliances")
        element.click()

Upvotes: 0

k.s. Karthik
k.s. Karthik

Reputation: 761

If you have fixed strings in your HTML code, there is no need to use contains() method in xpath. Please use text() method of xpath:

driver.findElement(By.xpath(.//*[text()='Appliances'])).click();

The reason to use this is, if your HTML code contains two or more elements with the word "Applicances", it would not select any element. So, in order to avoid that ambiguity we can use text()= directly.

Hope this helps.

Upvotes: 0

Strik3r
Strik3r

Reputation: 1057

Try the below one. Hope it helps.

driver.find_element_by_xpath("//*[text()='For Sale']") 

Upvotes: 4

bogdan.mustiata
bogdan.mustiata

Reputation: 1845

In Selenium the XPath finding it's a bit broken for recursive searches of elements that don't specify the tag name. So don't use: //*[].

Furthermore the XPath is a bit broken. In your examples you are searching for an element that has an attribute named "span" that contains the whatever string.

It should look like this:

driver.find_element_by_xpath("//a[contains(string(.),'For Sale']").click()

If you want, you can try germanium, a free test framework that I wrote, that deals with this kind of inconsistencies and more. In germanium the same code looks like: click(Text("Other Home Appliances"))

Upvotes: 1

Related Questions