How to find parent elements by python webdriver?
Asked Answered
D

4

90

Is there any methods for python+selenium to find parent elements, brother elements, or child elements just like

driver.find_element_parent? or
driver.find_element_next? or
driver.find_element_previous?

eg:

<tr>
  <td> 
     <select>
        <option value=0, selected='selected'> </option> 
        <option value=1, > </option>
        <option value=2,> </option>
     </select>
   </td>
   <td> 'abcd'
     <input name='A'> </input>
    <td>
<tr>

I've tried like below, but fail:

input_el=driver.find_element_by_name('A')
td_p_input=find_element_by_xpath('ancestor::input')

How can I get the parent of input element and then, finally, get the option selected?

Dianthus answered 6/8, 2013 at 12:8 Comment(0)
F
165

You can find a parent element by using .. xpath:

input_el = driver.find_element_by_name('A')
td_p_input = input_el.find_element_by_xpath('..')

What about making a separate xpath for getting selected option, like this:

selected_option = driver.find_element_by_xpath('//option[@selected="selected"]')
Flinch answered 6/8, 2013 at 12:16 Comment(6)
Just to add detail: ../ syntax doesn't work, ./.. and ./../.. work as expected. Don't add the trailing slash.Travel
bu_editor.find_element_by_xpath('..') AttributeError: 'NoneType' object has no attribute 'find_element_by_xpath' - why im getting this ?Spontaneity
@Martlark the parent attribute of an element is of type WebDriver, so it's not an element of type WebElementInfrastructure
@AlessandroDaRugna is there a way to get the next immediate child of the element in a similar fashion?Streetman
check out this site for more Xpath commands - scientecheasy.com/2019/08/xpath-axes.htmlMylesmylitta
Which is now input_el.find_element(By.XPATH, '..') as of selenium 4.3.0.Eurythermal
C
22

From your example, I figure you only want the selected option within a table-row if and only if this row also has an input element with the name "A", no matter where in the html-tree this element resides below the row-element.

You can achieve this via the xpath ancestor-axis.

For the sake of better readability I will show how to do this step by step (but you can actually put everything in only one xpath-expression):

# first find your "A" named element
namedInput = driver.find_element_by_name("A");
        
# from there find all ancestors (parents, grandparents,...) that are a table row 'tr'
rowElement = namedInput.find_element_by_xpath(".//ancestor::tr");
        
# from there find the first "selected" tagged option
selectedOption = rowElement.find_element_by_xpath(".//option[@selected='selected']");
Cleora answered 30/6, 2015 at 10:17 Comment(2)
is there a way to get the children in a similar fashion?Streetman
sure there is. if you really just want "children" that is only elements that are 1 layer below the parent element, then use "child" instead of "ancestor". if you're interested in all elements below a parent then use "descendant" instead of ancestor.Cleora
H
4

One of the possible ways to navigate to element under same hierarchy is to use /../ in xpath as shown below:

current_element = driver.find_element_by_xpath('//android.view.ViewGroup/android.widget.RelativeLayout/android.widget.TextView[@text="Current element text"]/../android.widget.TextView[@text="Next element text"]')

Here it will:

  1. Firstly navigate to android.widget.TextView[@text = "Current element text"]
  2. Then it will go back to parent element i.e android.widget.RelativeLayout and select the next android.widget.TextView[@text="Next element text"] under the same hierarchy.
Hazem answered 5/1, 2018 at 8:38 Comment(1)
this works really well but the example above isn't the greatest. Check this out, it finds an element and then navigates to the parent div: driver.find_element_by_xpath("//div[contains(text(),'floor price')]/../div").textDilatory
T
1

Repeatedly calling element.find_element_by_xpath('..') doesn't seem to work.

If you want to go more than one parent up, you can do:

from selenium.webdriver.remote.webelement import WebElement

def findAncestors(element: WebElement) -> list[WebElement]:
    # return all ancestors: [parent, ..., <html>]
    return element.find_elements(By.XPATH, ".//ancestor::*")

def findParent(element: WebElement) -> WebElement | None:
    ancestors = findAncestors(element)
    return ancestors[0] if ancestors else None
Toga answered 28/2, 2023 at 18:20 Comment(1)
Interesting? I didn't have any problems using find_element(By.XPATH, "..") multiple times with Python 3.8.3, Selenium 4.11.2 and geckodriver 0.33.0. In my testing, I had a password-input in a table-cell (TD) and respective parent table-row (TR). To get the TR, I just selected the input (input = driver.find_element(By.CSS_SELECTOR, '[type="password"]')), then the TD (td = input.find_element(By.XPATH, "..")), and finally the TR (tr = td.find_element(By.XPATH, "..")). It works just fine for me.Tranche

© 2022 - 2024 — McMap. All rights reserved.