0

When using selenium to find an element tag using Xpath, it works using the xpath copied from chrome for that element, this was to test if it was working. Since the id element changes every time I open the webpage I am aware that this will cause an error in my web automation program, now from that same tag I am using the class element as it does not change every time I open the webpage but Selenium fails to locate that element at all. When I change the element in xpath to class with its relative name from the xpath I initially copied and tested from the webbroswer. What may be the problem?

Here is a example of the html source code I am wanting to go to and the Xpath:

<div class="popover fade right in" role="tooltip" id="popover784483" style="top: -9px; left: 328.5px; display: block;">
    <div class="arrow" style="top: 88.9423%;"></div>
    <h3 class="popover-title">
        <font style="vertical-align: inherit;">
            <font style="vertical-align: inherit;">Member details</font>
        </font>
    </h3>
    <div class="popover-content">
        <img class="center-block" src="http://api.vdarts.net:8080/picture/portrait/default.png" style="max-width:200px;height:auto;">
        <hr>
        <font style="vertical-align: inherit;">
            <font style="vertical-align: inherit;">Account: CapitainJack </font>

Xpath intitially used but id changes:

//*[@id="popover784483"]/div[2]/font[1]/font

Xpath to be used:

//*[@class="popover fade right in"]/div[2]/font[1]/font
  • Post your error message for the second XPath. – Ratmir Asanov Feb 14 '19 at 15:14
  • Try a CSS selector, `div[id^='popover'] > div.popover-content > font > font`. You can do essentially the same thing with a modified version of your XPath, `//div[starts-with(@id,'popover')]/div[2]/font[1]/font`. Using indices is generally a bad idea since the HTML can change and your locator won't adapt, e.g. it will always use the 2nd div, etc. – JeffC Feb 14 '19 at 16:24
  • Please update your question title... `Python 3.7, Selenium 3.141.0` is not a question. – JeffC Feb 14 '19 at 16:50

2 Answers2

0

There are many ways to approach this issue.

You can match partial Text content Xpath like

//*[contains(text(), 'Account')]

You can use Img tag and following font like

(//img//following::font)[2]
Naveen
  • 770
  • 10
  • 22
  • I've tried both your options, the second option works but does not retrieve exactly what I want. The error message I am getting for your first option: Message: no such element: Unable to locate element: {"method":"xpath","selector":"//*[@id=contains(text(), 'popover')]/div[2]/font[1]/font"} – itsnotdxnny Feb 19 '19 at 11:02
  • Try changing the order in the xpath and checking with the Chrome Dev tools. A good how to is available [here](https://stackoverflow.com/a/22573161/7964299). – Naveen Feb 19 '19 at 13:23
  • Ok I tried something different and the xpath works when I search for it in my browser. This is thew new error message. What may be the problem? – itsnotdxnny Feb 20 '19 at 15:02
  • Message: invalid selector: The result of the xpath expression "//*/div[starts-with(@id, "popover")]/div[2]/text()[1]" is: [object Text]. It should be an element. – itsnotdxnny Feb 20 '19 at 15:02
  • Most probably issue with the quotes. try like "//*/div[starts-with(@id, 'popover')]/div[2]/text()[1]" – Naveen Feb 21 '19 at 09:58
  • That's not the issue selenium needs to find an element. I need to extract the text at that place in the web page source code. The xpath works fine in google chrome dev tools. I need to extract the text – itsnotdxnny Feb 22 '19 at 15:16
  • Can you please, add the solution and mark it as answer? – Naveen Feb 24 '19 at 09:41
-1

I would recommend you use CSS selectors instead.

Compound class names are when an element has multiple classes separated by spaces. E.g. <div class="class1 class2 class3"></div>

if you want to select element with all 3 classes (in any order), you can use:

element = driver.find_element_by_css_selector(".class1.class2.class3")

If you want to use XPath, I have found that the following method works (using the same example as above):

browser.find_elements_by_xpath("//*[contains(concat(' ',@class,' '),' class1 ') and contains(concat(' ',@class,' '),' class2 ') and contains(concat(' ',@class,' '),' class3 ')]")

Note: you can use different boolean operators to filter out certain class names (e.g. 'and' 'and not' etc)

Bruno Robert
  • 302
  • 2
  • 8
  • 1
    `You can't use compound class names with XPath in selenium.` This is not true. While this is not a good idea, it will work with XPath. I think you are maybe confusing `find_element_by_class_name()` which only takes one class name and will not allow compound class names. – JeffC Feb 14 '19 at 16:47
  • ... but I agree with using CSS selectors and the example you gave. – JeffC Feb 14 '19 at 16:48