93

I am trying to search for an element in a sub-element with Selenium (Version 2.28.0), but selenium des not seem to limit its search to the sub-element. Am I doing this wrong or is there a way to use element.find to search a sub-element?

For an example I created a simple test webpage with this code:

<!DOCTYPE html>
<html>
    <body>
        <div class=div title=div1>
            <h1>My First Heading</h1>
            <p class='test'>My first paragraph.</p>
        </div>
        <div class=div title=div2>
            <h1>My Second Heading</h1>
            <p class='test'>My second paragraph.</p>
        </div>
        <div class=div title=div3>
            <h1>My Third Heading</h1>
            <p class='test'>My third paragraph.</p>
        </div>
    </body>
</html>

My python (Version 2.6) code looks like this:

from selenium import webdriver

driver = webdriver.Firefox()

# Open the test page with this instance of Firefox

# element2 gets the second division as a web element
element2 = driver.find_element_by_xpath("//div[@title='div2']")

# Search second division for a paragraph with a class of 'test' and print the content
print element2.find_element_by_xpath("//p[@class='test']").text 
# expected output: "My second paragraph."
# actual output: "My first paragraph."

If I run:

print element2.get_attribute('innerHTML')

It returns the html from the second division. So selenium is not limiting its search to element2.

I would like to be able to find a sub-element of element2. This post suggests my code should work Selenium WebDriver access a sub element but his problem was caused by a time-out issue.

Can anyone help me understand what is happening here?

Community
  • 1
  • 1
Dominic Larkin
  • 1,184
  • 3
  • 10
  • 18

6 Answers6

184

If you start an XPath expression with //, it begins searching from the root of document. To search relative to a particular element, you should prepend the expression with . instead:

element2 = driver.find_element_by_xpath("//div[@title='div2']")
element2.find_element_by_xpath(".//p[@class='test']").text
Mateen Ulhaq
  • 24,552
  • 19
  • 101
  • 135
p0deje
  • 3,903
  • 1
  • 26
  • 37
  • 5
    This is an unfortunate design error in WebDriver that has been enshrined as a feature. All other `element.find_element_by_whatever()` methods in WebDriver perform the the search *within the context of the specified element*. find_element_by_xpath() does not. [Selenium bug #403](http://code.google.com/p/selenium/issues/detail?id=403) goes into more detail. – Ross Patterson Dec 27 '12 at 19:55
  • 10
    That's not design error of WebDriver, that's what XPath specification demands. – p0deje Dec 28 '12 at 05:02
  • That's definitely not a design error--it's how all DOM selections work in javascript... – duhaime Dec 30 '20 at 14:36
  • I recommend this site to learn different XPath commands - https://www.scientecheasy.com/2019/08/xpath-axes.html – Herker Apr 08 '21 at 12:20
7

Use the following:

element2 = driver.find_element_by_cssselector("css=div[title='div2']")
element2.find_element_by_cssselector("p[@class='test']").text 

Please let me know if you have any problems.

Chris
  • 3,462
  • 20
  • 32
user3487861
  • 340
  • 2
  • 2
3

I guess,we need use method "By" from webdriver.common.by when use "driver.find_element".

So...the code must be:

from selenium import webdriver

driver = webdriver.Firefox()
from selenium.webdriver.common.by import By

element2 = driver.find_element(By.XPATH, "//div[@title='div2']")
element2.find_element(By.XPATH, ".//p[@class='test']").text
1

This is how you search for element or tag in CSS subclass and I believe that it works for multilevel situation as well:

Sample HTML:

<li class="meta-item">
 <span class="label">Posted:</span>
 <time class="value" datetime="2019-03-22T09:46:24+01:00" pubdate="pubdate">22.03.2019 u 09:46</time>
</li>

This is how you would get pubdate tag value for example.

published = driver.find_element_by_css_selector('li>time').get_attribute('datetime')
Hrvoje
  • 13,566
  • 7
  • 90
  • 104
0

Chrome Webdriver :

element = driver.find_element_by_id("ParentElement")
localElement = element.find_element_by_id("ChildElement")
print(localElement.text)
svvc
  • 33
  • 7
0

Find The Child of any Elements

parent = browser.find_element(by=By.XPATH,value='value of XPATH of Parents')
    child=parent.find_elements(by=By.TAG_NAME,value='value of child path')