Python webdriver: get XPATH from innerHTML - python

Is there a way to get the xpath of an webelement knowing only its innerHTML value?
Say I've got a 'Save' button, which is a button with text "Save". Say that the button can change its location on the page with subsequent updates to the system, therefore changing its xpath every time.
Here is an example bit from the page source:
<button ng-click="Model.Save()" ng-disabled="Model.SavingChecklist" href="javascript:void(0)" class="btn" translate="">
<span class="ng-scope">Save</span>
</button>
I want to search the page for the innerHTML value "Save" and return the xpath (of the second line).
Note that "Save" is not a link.
Is it possible?

You can use following XPath to match any element with innerHTML="Save":
//*[text()="Save"]
or in your case:
//button/span[text()="Save"]

Related

i have a question to select xpath in sellenium(python)

i was trying to click some button in the page but it changes when it is available so that mine is not working.
basically, normally it's the only one section but changes into one that contains multiple buttons. and i am aiming to click buying or another buttons when it shows but i kept failing.
when it's unavailable(to click buying or shipping button), it looks like this.
<div class="XqRGHcrncz">
<ul class="_3YA58cPPsy">
<li class="_3nAZvQO51p N=a:pcs.mylist">
<a href="javascript:void(0)" role="button" class="_3Dy-2NaoiG" aria-pressed="false">
<span class="_3nBu7xChUl"><span class="blind">찜하기</span></span>
<em class="_1c-2nfzJqH">13</em></a></li></ul></div>
but when it is available, buying button appears. everything is same but the starting from
li class, it changes a bit.
li class became
<li class="_3nAZvQO51p N=a:pcs.mylist">
and the rest changed too.
<a href="javascript:void(0)" class="OgETmrvExa">
<span class="blind">구매하기</span>
how can i make xpath to click the element that shows only available?
the main problem is that div is changing.
xpath is sometimes
//*[#id="content"]/div/div[2]/div[2]/fieldset/div[7]/ul[1]/li/a
but sometimes it is
//*[#id="content"]/div/div[2]/div[2]/fieldset/div[8]/ul[1]/li/a
so that the div[] is changing. i tried css selector to click it when it turned into new page,
buy=driver.find_css_selector(div.XqRGHcrncz)
lists = buy.find_elements_by_tag_name("ul")
if len(lists) == 2: buy.click()
but when the page is loaded to available, it is not working at all...
i was trying to use xpath like this,
while True:
lists = buy.find_elements_by_tag_name("ul")
if len(lists) == 2:
break
else:
print("구매불가")
driver.refresh()
driver.implicitly_wait(10)
and then
driver.implicitly_wait(10)
xpath='//*[#id="content"]/div/div[2]/div[2]/fieldset/div[8]/ul[1]/li/a'
driver.find_element_by_xpath(xpath).click()
but as i mentioned, the xpath is changing and there is no use. the div[number] <- this changes so that it does not working as it is wrong xpath.
what should i do?? i would be really appreciate if anyone helps me.
(just in case, this is my page that i want to click when it became available...
https://smartstore.naver.com/hwaflora/products/5192517936 thank you)
Try to find element by text, is it stable?구매하기
so the code looks like that:
driver.find_element(By.XPATH, "//span[text()='구매하기']"
or by preceding xpath feature:
driver.find_element(By.XPATH, "//a/preceding::span[text()='찜하기']")
The xpath of your element is
String button = "//li[contains(#class,'_3nAZvQO51p N')]/a"
Now, you mentioned that until it is available there are more elements below it, for example this:
String loading = "//li[contains(#class,'_3nAZvQO51p N')]/a//em"
You can wait until this element disappears. The syntax in Java is:
WebDriverWait wait = new WebDriverWait(driver, 30);
wait.until((ExpectedConditions.invisibilityOfElementLocated(By.xpath(loading))));
Now you can find and click the button element

Can't dfferentiate between two selectors meant to perform one specific action

I've written a script in python in combination with selenium to click on a button named as follow located in a webpage. The thing is when I try with two different selectors, they both can click on the same button.
First selector:
"a[href$='/follow']"
Second one:
"a[href$='/follow'] > button"
Portion of relevant html:
<div class="nZSzR">
<h1 class="fDxYl">
some royal personality
</h1>
<span class="VerifiedBadge" title="Verified">
Verified
</span>
<a class="BY3EC" href="/accounts/follow" rel="nofollow">
<button class="L3NKy" type="button">
Follow
</button>
</a>
</div>
Which way I should stick to and why?
MITHU,
The css selector you have a[href$='/follow'], represent an anchor tag with href attribute that ends with /follow
second one a[href$='/follow'] > button , targets a button whose parent is anchor tag.
So, you can clearly see in second css, there is a dependency of a button. So, if you can go ahead with just first you should give priority to that.
For this HTML :
<a class="BY3EC" href="/accounts/follow" rel="nofollow">
<button class="L3NKy" type="button">
Follow
</button>
</a>
Clearly first css has less dependency.
If it's anchor tag then answer is no need of css selector.
You can directly go ahead with LINK_TEXT or PARTIAL_LINK_TEXT
Sample code :
continue_link = driver.find_element_by_link_text('Continue')
continue_link = driver.find_element_by_partial_link_text('Conti')
For more go through this official link.
So the > is a child combinator meaning you will only match the right hand side if it is a child of the left hand side.
Depending on how consistent pages are I would look for a faster selector and in this case go with a third option of
#react-root a
This is using your link: https://www.instagram.com/cristiano/?hl=en
An id and type selector will be faster than especially when using find_element_by_css_selector as you only need first match

Click on element using selenium python which is under label class

I have a web page which i am automating, I can click on any other elements using xpath or name or ID, but this gets little tricky when the element which I want to click is inside label. Here is the example,
<div class="dv-widget dv-deco-def dv-sz-med dv-map-sw">
<input name="l_maps" id="grp_perc" value="0" class="map_HD dv-radio-swr" type="radio">
<label for="grp_percentage" class="dv-radio-swl" onclick="">%</label>
<input name="l_maps" id="grp_count" value="1" class="map_HD dv-radio-swr" checked="" type="radio">
<label for="grp_multiply" class="dv-radio-swl" onclick="">*</label></div>
I need to click on the radio buton with the text % on it, I tried several option using xpath and CSS and ID but nothing seems to find that element under that label. I need help on this guys please. Thank you in advance.
This is kind of a strange situation. Typically the for attribute of the LABEL matches the ID of the INPUT that it corresponds to, e.g.
<input id="name" ... >
<label for="name" ... >
But in this case it doesn't match. We can get around it pretty easily. You can search for the element that contains the % text using XPath and then find the preceding INPUT.
//label[.='%']/preceding-sibling::input
If you plan to use this elsewhere also, I would suggest that you put this into a function and pass in the LABEL text, e.g. % and feed that into the locator to click the matching INPUT.
To click on the radio button with the text as % you can use either of the following lines of code :
Using preceding :
driver.find_element_by_xpath("//label[#class='dv-radio-swl' and #for='grp_percentage']//preceding::input[1]").click()
Using preceding-sibling :
driver.find_element_by_xpath("//label[#class='dv-radio-swl' and #for='grp_percentage']//preceding-sibling::input[1]").click()
Using ancestor :
driver.find_element_by_xpath("//label[#class='dv-radio-swl' and #for='grp_percentage']//ancestor::input[1]").click()
Update
As per the first part of the xpath I have provided it correctly identifies the <label> element with text as %. See the snapshot :
Now, appending preceding makes no mistake to identify the previous <input> tag. See snapshot :
So in all means our xpath is correct. Possibly, you need to induce a waiter for the element to be clickable as follows :
WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, "//label[#class='dv-radio-swl' and #for='grp_percentage']//preceding::input[1]"))).click()
If you are still unable to locate the element check the HTML if the element is within an <iFrame> tag and you will find a detailed discussion in How can I select a html element no matter what frame it is in in selenium?

Find Label in Selenium Python

I am using Selenium PhantomJS to perform headless dynamic scraping. I was able to extract all information except popups triggered by an ng-click, such as:
<button href="#" ng-click="navigation.login({edu:false})">login</button>
<a class="btn btn-primary" ng-click="login()">signup</a>
I want to get the tag that contains ng-click label, so that I can perform onclick activity and extract information from it.
The ng-click value and tag can be anything, I just want to search whether a tag contains ng-click or not, and if it is then return that tag.
I don't want to use regex or something like that.
The most simple solution is using XPath to check length of value of ng-click.
elements = driver.find_elements_by_xpath("//*[string-length(#ng-click) > 1]")
for element in elements:
element.click()
It works.
elements = driver.find_elements_by_xpath("//*[(#ng-click)]")

clicking on a link with the same href value using selenium python

I have a html code that has two links but both the links have the same href value, but the onclick and the text are different.
I wasn't sure as to how to access the second link.
I tried using driver.find_element_by_link_text('text'), but I get a no such element found error.
<div id="member">
<"a href="#" onclick="add_member("abc"); return false;">run abc<"/a>
<br>
<"a href="#" onclick="add_member("def"); return false;">run def<"/a>
</div>
There are multiple options to get the desired link.
One option would be to get use find_element_by_xpath() and check onclick attribute value:
link = driver.find_element_by_xpath('//div[#id="member"]/a[contains(#onclick, "add_member(\"def\")")]')
link.click()
Another one would be to simply find both links and get the desired one by index:
div = driver.find_element_by_id('member')
links = div.find_elements_by_tag_name('a')
links[1].click()
Which option to choose depends on the whole HTML content. Hope at least one of two suggested solutions solves the issue.

Categories