92

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?

0

4 Answers 4

170

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"]')
Sign up to request clarification or add additional context in comments.

6 Comments

Just to add detail: ../ syntax doesn't work, ./.. and ./../.. work as expected. Don't add the trailing slash.
bu_editor.find_element_by_xpath('..') AttributeError: 'NoneType' object has no attribute 'find_element_by_xpath' - why im getting this ?
@Martlark the parent attribute of an element is of type WebDriver, so it's not an element of type WebElement
@AlessandroDaRugna is there a way to get the next immediate child of the element in a similar fashion?
check out this site for more Xpath commands - scientecheasy.com/2019/08/xpath-axes.html
|
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']");

2 Comments

is there a way to get the children in a similar fashion?
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.
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.

1 Comment

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").text
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

1 Comment

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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.