'Selenium - Get a list of all the elements between two h1 elements

I have a webpage with the following HTML snippet within it

<h1> ... </h1>
<p> ... </p>
<p> ... </p>
<h1> ... </h1>
<h2> ... </h2>
<p> ... </p>
<h3> ... </h3>
<p> ... </p> 
<p> ... </p>
<h1> ... </h1>

Given the xpath of the first h1 element is //*[@id="profile"]/div[2]/div[2]/div/h1[1], and the xpath of the last h1 element is //*[@id="profile"]/div[2]/div[2]/div/h1[3], how can I get a list with references to all the elements between these two elements?



Solution 1:[1]

The following xpath could work if you add something unique attribute for the first and third h1.

"//*[preceding-sibling::h1[@some unique att] and following-sibling::h1[@some unique att]"

Solution 2:[2]

Consider a chunk of HTML like this:

<body>
    <h1 id="profile"> 1st h1 </h1>
    <p> 1st p </p>
    <p> 2nd p </p>
    <h1> 2nd h1 </h1>
    <h2> 1st h2 </h2>
    <p> 3rd p </p>
    <h3> 1st h3 </h3>
    <p> 4th p </p> 
    <p> 5th p</p>
    <h1 id="profile"> 3rd h1 </h1>
</body>

The items you want have a (common) parent, namely the body element. Hence, by locating the first h1 you can locate that parent. Then you can locate all of the siblings of that first h1.

>>> from selenium import webdriver
>>> from selenium.webdriver.common.keys import Keys
>>> driver = webdriver.Chrome()
>>> driver.get('file://c:/scratch/temp.htm')
>>> parent = driver.find_element_by_xpath('//h1[@id="profile"]/..')
>>> for child in parent.find_elements_by_xpath('./child::*'):
...     child.text, child.get_attribute('id')
... 
('1st h1', 'profile')
('1st p', '')
('2nd p', '')
('2nd h1', '')
('1st h2', '')
('3rd p', '')
('1st h3', '')
('4th p', '')
('5th p', '')
('3rd h1', 'profile')

In this loop child will contain the references you seem to want. You can use what get_attribute returns to ignore the siblings that you don't want.

Solution 3:[3]

In C# I would do something like this

static int void test(ChromeDriver driver)
    {
        int counter = 0;
        try
        {
            for (int i = 1; i <= 3; i++)
            {
                string getdata = driver.FindElementByXPath("//*[@id=""profile""]/div[2]/div[2]/div/h1[" + i +]").Text;
                    counter++;

            }
        }
        catch
        {
            return counter;
        }
    }

In a loop search for each element by increment the Xpath value +1

div[2]/div[2]/div/h1[1]
div[2]/div[2]/div/h1[2]
div[2]/div[2]/div/h1[3]

For an exception when the loop reaches a value it cannot find, then return the counted value. This way you know the [3] elements exist. You can click write whatever you need to click anyone you wish. Sorry it's in C#, but hopefully the logic works for you.

Solution 4:[4]

Deeply qualified xPath are an anti-pattern as a element location strategy, Instead consider the following list, starting with the target element for the following and look outwards not top down.

  1. ID attribute for globally unique items
  2. Name attribute for locally unique items
  3. focused xPath for maximum control
  4. Class Name with frameworks
  5. Content Text

Best practice for front-end development make pages tractable to automated testing with Selenium WebDriver.

Solution 5:[5]

The following xpath will let you get in between values.

//*[preceding-sibling::h1]

Solution 6:[6]

In your case, I think the best way is this :

# Get the starting element
after = driver.find_elements_by_xpath('//*[@id="profile"]/div[2]/div[2]/div/h1[1]/following-sibling::p')

# Get the ending element
before = driver.find_elements_by_xpath('//[@id="profile"]/div[2]/div[2]/div/h1[3]/preceding-sibling::p')

# Get the middle (= the intercept)
middle = [elem for elem in after if elem in before]

After this you can use each element of the middle to do whatever you want (because they still are of selenium type). Hope it will help you !

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Grasshopper
Solution 2 Bill Bell
Solution 3 agleno
Solution 4
Solution 5 Anurag Reddy
Solution 6