0

I've got markup of the following format I'm attempting to work with using Selenium/Python:

    <tr>
        <td><a href="www.google.com">google</a></td>
        <td>useless text</td>
        <td>useless text2</td>
        <td>useless text3</td>
        <td><a href="needle@email.com">emailaddress</a></td>
    </tr>

The idea being that given a known email address (part of the href in the emailaddress td), I can get to (and click) the a in the first td. It looks like xpath is the best choice to accomplish this with Selenium. I'm trying the following xpath:

//*[@id="page_content"]/table/tbody/tr[2]/td[2]/div/table[1]/tbody/tr/td[4]/a[contains(@href, "mailto:needle@email.com")]/../../td/a[0]

But I'm getting this error:

selenium.common.exceptions.NoSuchElementException: Message: no such element: Unable to locate element: {"method":"xpath","selector":"xpathhere"}

I do know the xpath to get to the "needle@email.com" a is correct, as it's just copied from chrome dev tools, so the error must be with the part of the xpath after reaching the first a element. Can anyone shed some light on the problem with my xpath?

Marcatectura
  • 1,721
  • 5
  • 30
  • 49
  • maybe just `//a[contains(@href, "needle@email.com")]` ? – splash58 May 08 '17 at 17:07
  • The problem is I'm attempting to retrieve the `a` in the first `td`, so I need to figure out how to get back to that level once the "needle@email.com" `a` is matched. – Marcatectura May 08 '17 at 17:12
  • You should avoid using indexes, always use something you know will not change, like part of an attribute for example, using indexes is a bad practice and not very flexible. – lauda May 08 '17 at 17:28
  • The best answer is @Andersson's. No index, robust against unexpected issues and Selenium state of the art practices. – keepAlive May 08 '17 at 18:01

4 Answers4

2

Try to use below code:

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

xpath = '//td[a[@href="needle@email.com"]]/preceding-sibling::td/a'
wait(driver, 10).until(EC.element_to_be_clickable((By.XPATH, xpath))).click()

This should allow you to match first link based on href attribute of the last link in table row (tr) and click it once it became clickable

Andersson
  • 51,635
  • 17
  • 77
  • 129
1

First, note that (this may be a meaningless typo) you are looking for "mailto:needle@email.com" while the value of your href attribute is "needle@email.com".

Second, you actually know how to get back [...]. But Xpath indexing starts with 1. Thus why this 'a[0]', is this also a meaningless typo ?

Anyway, this xpath would get your sibling

'//a[contains(@href, "needle@email.com")]/../../td[1]/a[1]'

Or more accurately than using contains (since you may have other email adresses that can be matched, e.g. "otherneedle@email.com")

'//a[@href="needle@email.com"]/../../td[1]/a[1]'

Or even better, i.e. with no index and no parent/child like exploration.

'//td[a[@href="needle@email.com"]]/preceding-sibling::td/a'

All tested.

Community
  • 1
  • 1
keepAlive
  • 6,369
  • 5
  • 24
  • 39
0

Try to find the tr that contains that email, and click on the first link from it.

//tr[.//a[contains(@href, 'your_email')]]//a

or

//tr[.//a[contains(@href, 'your_email')]]//a[@href]

or

//tr[.//a[contains(@href, 'your_email')]]//a[contains(@href, 'common_url_part')]
lauda
  • 4,153
  • 2
  • 14
  • 28
0

Your HTML should be this.

<tr>
    <td><a href="www.google.com">google</a></td>
    <td>useless text</td>
    <td>useless text2</td>
    <td>useless text3</td>
    <td><a href="mailto:needle@email.com">emailaddress</a></td>
</tr>

Otherwise, your user can click on the link until he or she works himself into a frenzy. :)

Then you can do this in selenium.

>>> from selenium import webdriver
>>> driver = webdriver.Chrome()
>>> driver.get("file://c:/scratch/temp2.htm")
>>> link = driver.find_element_by_xpath('.//a[contains(@href,"needle@email.com")]')
>>> link.click()

I've used contains because an email address in a link can be something like mailto:Jose Greco <needle.email.com>.

PS: And incidentally I've just executed this stuff on my machine.

Bill Bell
  • 21,021
  • 5
  • 43
  • 58