Xpath Selenium- How to locate a element by the sub text - python

Hope you´re really fine and can help me with this short question.
I´m trying to locate the following object id=C39_W133_V136_thtmlb_button_27 but using the text that is located after an span (text = "Edit"). Please I tried different ways but didn´t work till now, any idea?
<a href="javascript:void(0)" class="th-bt th-bt-icontext-dis icon-font" tabindex="-1" oncontextmenu="return false;" ondragstart="return false;" id="C39_W133_V136_thtmlb_button_27">
::before
<img class="th-bt-img" src="/SAP/BC/BSP/SAP/thtmlb_styles/sap_skins/belize/images/1x1.png">
<span class="th-bt-span"><b class="th-bt-b">Edit</b></span>
<b class="th-bt-b">Edit</b>
</a>

In order to locate an element using text contained in an element, the only option is to use XPath.
//a[./b[.='Edit']]
^ Start at the top of the document and find an A tag
^ ...that has a descendant B tag
^ ...that contains the text 'Edit'

To locate the <a> element which have a descended <span> with text as Edit you need to induce WebDriverWait for the visibility_of_element_located() and you can use either of the following Locator Strategies:
Using XPATH:
element = WebDriverWait(driver, 20).until(EC.visibility_of_element_located((By.XPATH, "//a[contains(#id, 'thtmlb_button')][.//b[text()='Edit']]")))
Note : You have to add the following imports :
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC

Related

Pull data from a div class Python Selenium

I'm trying to pull a specific number out of a div class in Python Selenium but can't figure out how to do it. I'd want to get the "post_parent" ID 947630 as long as it matches the "post_name" number starting 09007.
I'm looking to do this across multiple "post_name" classes, so I'd feed it something like this: search_text = "0900766b80090cb6", but there will be multiple in the future so it has to read the "post_name" first then pull the "post_parent" if that makes sense.
Appreciate any advice anyone has to offer.
<div class="hidden" id="inline_947631">
<div class="post_title">Interface Converter</div>
<div class="post_name">0900766b80090cb6</div>
<div class="post_author">28</div>
<div class="comment_status">closed</div>
<div class="ping_status">closed</div>
<div class="_status">inherit</div>
<div class="jj">06</div>
<div class="mm">07</div>
<div class="aa">2001</div>
<div class="hh">15</div>
<div class="mn">44</div>
<div class="ss">17</div>
<div class="post_password"></div>
<div class="post_parent">947630</div>
<div class="page_template">default</div>
<div class="tags_input" id="rs-language-code_947631">de</div>
</div>
If you see <div class="post_name">0900766b80090cb6</div> this and <div class="post_parent">947630</div> are siblings nodes to each other.
You can use xpath -> following-sibling like this:
Code:
search_text = "0900766b80090cb6"
post_parent_num = driver.find_element(By.XPATH, f"//div[#class='post_name' and text()='{search_text}']//following-sibling::div[#class='post_parent']").text
print(post_parent_num)
or Using ExplicitWait:
search_text = "0900766b80090cb6"
post_parent_num = WebDriverWait(driver, 20).until(EC.visibility_of_element_located((By.XPATH, f"//div[#class='post_name' and text()='{search_text}']//following-sibling::div[#class='post_parent']"))).get_attribute('innerText')
print(post_parent_num)
Imports:
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
Update:
NoSuchElementException:
Please check in the dev tools (Google chrome) if we have unique entry in HTML-DOM or not.
xpath that you should check :
//div[#class='post_name' and text()='0900766b80090cb6']//following-sibling::div[#class='post_parent']
Steps to check:
Press F12 in Chrome -> go to element section -> do a CTRL + F -> then paste the xpath and see, if your desired element is getting highlighted with 1/1 matching node.
If this is unique //div[#class='post_name' and text()='0900766b80090cb6']//following-sibling::div[#class='post_parent'] then you need to check for the below conditions as well.
Check if it's in any iframe/frame/frameset.
Solution: switch to iframe/frame/frameset first and then interact with this web element.
Check if it's in any shadow-root.
Solution: Use driver.execute_script('return document.querySelector to have returned a web element and then operates accordingly.
Make sure that the element is rendered properly before interacting with it. Put some hardcoded delay or Explicit wait and try again.
Solution: time.sleep(5) or
WebDriverWait(driver, 20).until(EC.visibility_of_element_located((By.XPATH, "//div[#class='post_name' and text()='0900766b80090cb6']//following-sibling::div[#class='post_parent']"))).text
If you have redirected to a new tab/ or new windows and you have not switched to that particular new tab/new window, otherwise you will likely get NoSuchElement exception.
Solution: switch to the relevant window/tab first.
If you have switched to an iframe and the new desired element is not in the same iframe context then first switch to default content and then interact with it.
Solution: switch to default content and then switch to respective iframe.
I don't see any specific relation between "post_parent" ID 947630 and "post_name" number starting 09007. Moreover, the parent <div> is having class="hidden".
However, to pull the specific number you can use either of the following locator strategies:
Using css_selector:
print(driver.find_element(By.CSS_SELECTOR, "div[id^='inline'] div.post_parent").text)
Using xpath:
print(driver.find_element(By.XPATH, "//div[starts-with(#id, 'inline_')]//div[#class='post_parent']").text)
Ideally you need to induce WebDriverWait for the presence_of_element_located() and you can use either of the following locator strategies:
Using CSS_SELECTOR:
print(WebDriverWait(driver, 20).until(EC.presence_of_element_located((By.CSS_SELECTOR, "div[id^='inline'] div.post_parent"))).text)
Using XPATH:
print(WebDriverWait(driver, 20).until(EC.presence_of_element_located((By.XPATH, "//div[starts-with(#id, 'inline_')]//div[#class='post_parent']"))).text)
Note: You have to add the following imports :
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
You can create a method and use the following xpath to get the post_parent text based on post_name text.
def getPostPatent(postname):
element=driver.find_element(By.XPATH,"//div[#class='post_name' and starts-with(text(),'{}')]/following-sibling::div[#class='post_parent']".format(postname))
print(element.get_attribute("textContent"))
getPostPatent('09007')
This will return value if it is matches the text starts-with('09007')
It seems parent class is hidden you need to use textContent to get the value.

Finding li element by text inside - Selenium Python

I have been trying to find a way to click a specific li element by using the text inside, however, whatever I try seems to not be finding the element.
The HTML is;
<ul class="shoes-sizen-mp" id="ul_top_hypers" style="overflow: auto;">
<li id="li_284" onclick="return select_size('284')"><a class="a_top_hypers"> 3.5 <span style="display: none">,</span><br> 35.5<br></a></li>
<li id="li_285" onclick="return select_size('285')"><a class="a_top_hypers"> 4 <span style="display: none">,</span><br> 36<br></a></li>
This is part of a list where you can select your size (such as 3.5,4,4.5,5). I want to be able to click the specific one by using the text such as 3.5, for example.
Edit
driver.find_element_by_xpath(f"//ul[#id='ul_top_hypers' and starts-with(#id, 'li_'][contains(text(),'{user_shoe_size}')]").click()
sleep(20)
Above is one of the many things I have tried to locate the element, but nothing just yet.
Any help would be greatly appreciated. Thanks a lot!
To click on dynamic induce WebDriverWait() and wait for element_to_be_clickable() and following xpath.
def click_size(size):
WebDriverWait(driver,10).until(EC.element_to_be_clickable((By.XPATH,"//ul[#class='shoes-sizen-mp']//li[contains(.,'{}')]".format(size)))).click()
click_size("3.5")
You need to import below libraries.
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

Access html text through python selenium

I am trying to get text (marked by hashtags).
<div class="XYZ">
<h5>
"
#######Reports due by##############
"
<span class="hbl" data-hint="task due date">
<i class="icon-boxy-sign"></i>
</span>
</h5>
<script type="jsv#61^"></script><script type="jsv#123_"></script>
<script type="jsv#60^"></script><script type="jsv#124_"></script>
<script type="jsv#59^"></script><p>#################07/10/2020#######################</p><script type="jsv/125^"></script>
<script type="jsv/52_"></script><script type="jsv/24^"></script>
<script type="jsv/42_"></script><script type="jsv/23^"></script>
</div>
Python line to get the text inside the hashtags:
txt = dat =wait(driver, 10).until(EC.visibility_of_element_located((By.CSS_SELECTOR, 'div[class="XYZ"]'))).text
I expect the line to print: "Reports due by" and "07/10/2020, I keep getting timeoutException and Unable to locate element errors.
Seems you were close. To extract the text (marked by hashtags) you have to induce WebDriverWait for the visibility_of_element_located() and you can use either of the following Locator Strategies:
Using CSS_SELECTOR:
print(WebDriverWait(browser, 20).until(EC.visibility_of_element_located((By.CSS_SELECTOR, "div.XYZ"))).get_attribute("title"))
Using XPATH:
print(WebDriverWait(browser, 20).until(EC.visibility_of_element_located((By.XPATH, "//div[#class='XYZ']"))).get_attribute("title"))
Note : You have to add the following imports :
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
Here you can find a relevant discussion on selenium.common.exceptions.NoSuchElementException: Message: no such element: Unable to locate element while trying to click Next button with selenium
Change By. CSS_SELECTOR to By.XPATH and update locator to '//div[#class='XYZ']'. Should work.

How to click the page link with selenium python

My error:
selenium.common.exceptions.NoSuchElementException: Message: no such element: Unable to locate element: {"method":"link text","selector":"entrar"}
I have the html below:
<a role="menuitem" href="/login" class="_yce4s5">
<div class="_hgs47m">
<div class="_10ejfg4u">
<div>
Entrar
</div>
</div>
</div>
</a>
I click on the then link entrar, the following code in selenium with python:
driver.implicitly_wait(10)
element = driver.find_element_by_link_text('Entrar')
element.click()
But It raises this NoSuchElementException.
Did you try to use Upper case for the first letter? like 'Entrar' instead of 'entrar'
You might try driver.find_element_by_partial_link_text('entrar') because there is probably other text in your link. I like getting element by xpath. It's pretty easy. If you have Firefox just get the add-on xpath finder to find the xpath to any element on a web page.
To click the page link with text as Entrar as the element is a dynamic element ou have to induce WebDriverWait for the desired element to be clickable and you can use either of the following solution:
Using CSS_SELECTOR:
WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.CSS_SELECTOR, "a[role='menuitem'][href='/login'] > div > div > div"))).click()
Using XPATH:
WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, "//a[#role='menuitem' and #href='/login']//div[normalize-space()='Entrar']"))).click()
Note : You have to add the following imports :
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC

Extract first span child with Selenium

I want to extract the first span with the text Extract this text. Already tried:
element.find_element_by_css_selector(".moreContent span:nth-child(1)").text.strip('"')
This is not working, I am not sure why. The output is just empty.
<p class="mainText">
Lorem Ipsum is simply dummy text of the printing and typesetting industry.
<span class="moreEllipses">… </span>
<span class="moreContent">
<span> Extract this text </span>
<span class="link moreLink">Show More</span>
</span>
</p>
However I am getting this, so Selenium finds the element but why the output is empty:
<selenium.webdriver.remote.webelement.WebElement (session="e7012b303842651848aa0b0e40f5d5c1", element="df5644e9-fc98-4300-ad86-9ff433154d82")>
EDIT:
I managed to solve this by clicking on show more button. For some reason i can't extract the content if not visible even if present in page.
As per your cssSelector it seems you are targeting below
<span> Extract this text </span>
You can use below Xpath:
(//p[#class='mainText']//span[#class='moreContent']/span)[1]
OR
(//span[#class='moreContent']/span)[1]
Example Code:
element = driver.find_element_by_xpath("(//p[#class='mainText']//span[#class='moreContent']/span)[1]").text
To extract the text from the first <span> i.e. Extract this text you need to to induce WebDriverWait for the visibility_of_element_located() and you can use either of the following Locator Strategies:
Using CSS_SELECTOR and text property:
print(WebDriverWait(driver, 20).until(EC.visibility_of_element_located((By.CSS_SELECTOR, "p.mainText span.moreContent>span"))).text)
Using XPATH and get_attribute() method:
print(WebDriverWait(driver, 20).until(EC.visibility_of_element_located((By.XPATH, "//p[#class='mainText']//span[#class='moreContent']/span"))).get_attribute("innerHTML"))
Note : You have to add the following imports :
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC

Categories

Resources