0

I'm trying to select an element based on an already given element using Selenium and locators, but i'm trying to speed up the process and XPath isn't really helping me in this case.

This is the structure of the HTML i'm working with.

<div class="inner-article">
   <h1>
      <a class="name-link">
         Text 1
      </a>
   </h1>
   <p>
      <a class="name-link">
         Text 2
      </a>
   </p>
</div>

As of right now, I'm using these XPaths to find Text 1 and Text 2

text1 = driver.find_element_by_xpath("//a[contains(., 'Text 1')]")
text2 = driver.find_element_by_xpath("//a[contains(., 'Text 1')]/parent::h1/following-sibling::p/a[contains(., 'Text 2')]")

Since XPath has a noticeable delay, I was wondering if it's possible to use a different and much faster locator other than XPath. I can't really think of anything, because CSS selectors aren't an option and I can't think of a way to use the others.

undetected Selenium
  • 183,867
  • 41
  • 278
  • 352
Gulpy
  • 343
  • 1
  • 2
  • 4
  • For `Text 1` you have `find_element_by_link_text`, but if you are worried about performance this is worse than `xpath`. For `Text 2` you are using ancestor (`parent`) so `xpath` is your only option. – Guy Nov 04 '18 at 06:14
  • By the way, what you base *noticeable delay* on? it's true it has worsr performance than `by_class_name` or `by_id` or even `by_css_celector`, but it's a matter of milliseconds, not really noticeable, – Guy Nov 04 '18 at 06:16
  • I have a for loop that loops through a dictionary with values that are used for the Text 1 and Text 2 placeholders. I've tried find_element_by_link_text first in this loop and i noticed it was faster than using XPath, so I wouldn't say the delay was more than a few seconds, but if you'd check the python console, you could see the difference (using Pycharm). – Gulpy Nov 04 '18 at 06:20
  • Don't depend of printout to the console to measure time, it can be affected by many things. Try something like https://stackoverflow.com/a/889919/5168011 – Guy Nov 04 '18 at 06:32

2 Answers2

0

Simply find the index number of that x path and add by 1 to get the next adjacent xpath element.

iterlist = iter( driver.get_all_elements_by_xpath ("//a[contains(., 'Text 1')]"))
while xpathFound == False :
    myElement = next(iterlist)       # get the next item
    xpathFound = True if myElement == text1xpath else False
RasikhJ
  • 601
  • 5
  • 10
0

As the <a> node with text as Text 1 is always within grand parent node <div class="inner-article"> and parent node <h1> & the <a> node with text as Text 2 is always within grand parent node <div class="inner-article"> and parent node <p>, you can use either of the following solutions:

  • xpath for Text 1:

    element_text1 = driver.find_element_by_xpath("//div[@class='inner-article']/h1/a[@class='name-link' and contains(., 'Text 1')]")
    
  • xpath for Text 2:

    element_text2 = driver.find_element_by_xpath("//div[@class='inner-article']//p/a[@class='name-link' and contains(., 'Text 2')]")- `xpath` for _Text 1_:
    
    element_text1 = driver.find_element_by_xpath("//div[@class='inner-article']/h1/a[@class='name-link' and contains(., 'Text 1')]")
    
  • xpath for Text 2:

    element_text2 = driver.find_element_by_xpath("//div[@class='inner-article']//p/a[@class='name-link' and contains(., 'Text 2')]")
    
  • xpath for Text 1 and Text 2(wrt Text 1) :

    element_text1 = driver.find_element_by_xpath("//a[contains(., 'Text 1')]")
    element_text2 = driver.find_element_by_xpath("//a[contains(., 'Text 1')]//following::a[contains(., 'Text 2')]") 
    
undetected Selenium
  • 183,867
  • 41
  • 278
  • 352