Using CSS ":contains:" with WebDriver in Python - python

I'm migrating some Selenium WebDriver test cases from unittest to py.test and seeing an issue when I attempt to use the *:contains() command on a CSS Selector. Here's an example of a line that fails:
WebDriverWait(driver, 60).until(
expected_conditions.element_to_be_clickable((By.CSS_SELECTOR, "body.yui-skin-sam div[id=Navigation] ul[id=mainNav] li span:contains(Home)"))
)
Any time I've attempt this command with a CSS Selector that does not contain *:contains(), it works fine. Otherwise, I get either a TimeoutException or a InvalidElementStateException. I've also tried using the following instead:
expected_conditions.element_located_to_be_selected
" .element_to_be_clickable
" .element_to_be_selected
" .presence_of_element_located
" .text_to_be_present_in_element
" .visibility_of_element_located
I'm fairly sure my issue has more to do with attempting to use *:contains(). Attempting to use By.NAME, By.XPATH, or any other object name, it works fine. Here's what I'm looking at with respect to the HTML Source on the page:
</div>
<div id="HeaderBox">
<div id="Content">
<div id="Header">
<div id="Left">
<img src="/images/header_logo.png" />
</div>
<div id="Right">
<div id="Text">
<div id='active_conf'> running... </div><br>
Profile is unlocked. ( Lock
| Logout )<br>
</div>
</div>
</div>
<div id="Navigation">
<ul id="mainNav">
<li><span>Home</span></li>
<li><span>DataValues</span></li>
<li><span>Devices</span></li>
</ul>
Does anyone know of a way I can get this to work? Thanks ahead of time!

I'll preface this by saying I'm not very familiar with the Python bindings for Selenium (I use Java)... However, I had this same problem a while back. I was able to solve this by injecting Sizzle.js onto the DOM to aid element location. Sizzle brings with it the :contains() psuedo-class and support for other JQuery selectors as well.
I was able to find a small bit of info for Python HERE, but I'm sure there's more thorough information out there.

I was able to find a solution to this issue. For starters, as #Mark Rowlands mentioned above, contains() can't be used. I needed to make some changes to my CSS syntax as well so it would do a better job of pointing at the object I wanted to verify. Finally, since I have an attribute, a located, and a value [where the value is the text located in contains()], I needed a method that allowed for all 3, which in this case was the text_to_be_present_in_element method. So, to locate Home, I needed to do the following:
WebDriverWait(driver, 60).until(
expected_conditions.text_to_be_present_in_element((By.CSS_SELECTOR, "css=ul[id='mainNav'] > li:nth-of-type(1) > a > span"), "Home")
)
I also could have used a > span instead of the long form listed and probably could substitute nth-of-type for first-child. Now, if I want to locate one of the other values, devices for example, I needed to do the following:
WebDriverWait(driver, 60).until(
expected_conditions.text_to_be_present_in_element((By.CSS_SELECTOR, "ul[id='mainNav'] > li:nth-of-type(2) > a > span"), "DataValues")
)
While I'm sure there are other solutions, these are the ones that worked for me. Hope this helps someone out in the future.

Related

Can't find an element even though its brother element is found in Selenium Python?

I'm trying to get the content from a tag, but it raised NoSuchElement even though getting it from an another tag with the same level is successful.
This is the link to website: https://soundcloud.com/pastlivesonotherplanets/sets/spell-jars-from-mars
This is the html code that I access to:
<div class="fullHero__tracksSummary">
<div class="playlistTrackCount sc-font">
<div class="genericTrackCount sc-font large m-active" title="16 tracks">
<div class="genericTrackCount__title">16</div>
<div class="genericTrackCount__subtitle"> Tracks </div>
<div class="genericTrackCount__duration sc-type-small sc-text-body sc-type-light sc-text-secondary">56:07</div>
</div>
</div>
</div>
I'm trying to get the playlist's duration with this code:
try:
tmp=driver.find_element_by_xpath("//div[#class='fullHero__tracksSummary']")
duration=tmp.find_element_by_class_name("genericTrackCount__duration sc-type-small sc-text-body
sc-type-light sc-text-secondary").get_attribute('textContent')
print(duration)
except:
print("None")
It raised error NoSuchElement even though the other two tags was successful.
What is the problem and how can I fix it?
Thank your for your time.
I think you can try directly using xpath //div[contains(#class, 'duration')] OR
//div[contains(#class, 'playlistTrackCount')]/descendant::div[contains(#class, 'duration')]
Without looking at the page, you probably need to wait for the element to load.
You can use either time.sleep(5) 5 being the number of seconds to wait or WebDriverWait(driver, 20) with an expected condition
so your code would look like
import expected_conditions as EC
WebDriverWait(driver, 20).until(EC.visibility_of_element_located((By.CLASS_NAME, '"genericTrackCount__duration sc-type-small sc-text-body
sc-type-light sc-text-secondary"))).text
Also maybe the get_attribute('textContent') is failing, you can just use .text

Selenium select specific content with OR/AND operators - python

I am struggling with a problem in Selenium using Python.
This is a dummy draft of what I have.
<body>
<button info="content1" aria-label="1">"Click 1"</button>
<button info="content1" aria-label="2">"Click 2"</button>
<button info="content2" aria-label="2">"Click 2"</button>
<button info="content2" aria-label="4">"Click 4"</button>
<body>
My target is to select the button that has info="content1" and aria-label="2"
I have already tried
element=driver.find_element_by_css_selector('button[info="content1"] and button[aria-label="2"]')
But doesn't work and returns NoSuchElementException
Would you please help me?
Simply put the two bracketed attribute selectors next to each other with no and:
element = driver.find_element_by_css_selector('button[info="content1"][aria-label="2"]')

Which Selenium method or command can be used to click on the following buttons?

Which method in Selenium with python can be used to click on the following buttons?
Button nr. 1:
<a href="/help.html"> = $0
<i class="fa fa-question" aria-hidden="true"></i> HELP </a>
Button nr.2:
<a class="active-menu-item" href="/help/making_service_requests.html">Service Requests</a>
Button nr.3:
Transfer Service
I have already tried but wont work:
driver.find_element_by_xpath('//*[#id="topmenuheader"]/div/ul/li[3]/a').click()
driver.find_elements_by_partial_link_text("Transfer Service").click()
driver.find_element_by_class_name("btn").click()
I have encountered many instances where there are no id, no class etc, butand href available or an href with an html reference as mentioned above. These seem to be tricky as i have tried quite a few things. Maybe some of you have encountered these and could help out. Thanks
These should work for those 3 elements. I showed multiple ways of getting those a tags either by href, class or text.
driver.find_element_by_xpath("a[#href='/help.html']").click()
driver.find_element_by_xpath("a[#class='active-menu-item']").click()
driver.find_element_by_xpath("a[text()='Transfer Service']").click()
You can do this :
Driver = driver.find_element_by_xpath("path here")
Driver.click()

How to check checkbox using Selenium in Python

I have a problem with this checkbox. I tried to click searching element with id, name, XPath, CSS Selector and contains text and still I could not click on this checkbox. Additionally, I've tried with another site with similar HTML code and on this site, it was enough to look for id and click. Any ideas?
<div class="agree-box-term">
<input tabindex="75" id="agree" name="agree" type="checkbox" value="1">
<label for="agree" class="checkbox-special">* Zapoznałam/em się z Regulaminem sklepu internetowego i akceptuję jego postanowienia.<br></label>
</div>
Here is my Python code https://codeshare.io/5zo0Jj
I have used javaScript Executor and it clicks on the element.However I have also checked webdriver click is not working.
driver.execute_script("arguments[0].click();", driver.find_element_by_id("agree"))
I don't know why this is, but in my experience some boxes don't accept click but do accept a 'mousedown' trigger.
try:
driver.execute_script('$("div.agree-box-term input#agree").trigger("mousedown")')
This solution does rely on jquery being on the page, if it's not we can write it in javascript
r = driver.find_element_by_xpath("//*[#id="form-order"]/div[2]/div[4]/label")
r.click()
Does this work for you? Sometimes it's just a question of selecting the right xpath, or adding the brackets after click.
Does your code contain nested html tags? For example:
<html>
<div>
<p> Some text </p>
<html>
That block can't be traversed!
</html>
</div>
</html>
Anything inside the second HTML tags can't be traversed/accessed. Try to see if that's the case.
In any other case the following code ran perfectly fine for your snippet:
driver.find_element_by_css_selector('#agree').click()

Python selenium - get element by its xPath and access it

I am using Python and Selenium to scrape a webpage, in some cases, I can't get it to work,
*
I would like to access the element with text 'PInt', wich is the second link in the below code.
The xPath for it (copied from Developer console) is: //[#id="submenu1"]/a[2]
<div id="divTest" onscroll="SetDivPosition();" style="height: 861px;">
<div class="menuTitle" id="title1">
</div>
<div class="subtitle" id="submenu1">
<img src="images/spacer.gif" border="0" width="2px" height="12px">
Mov<br>
<img src="images/spacer.gif" border="0" width="2px" height="12px">
PInt<br>
<img src="images/spacer.gif" border="0" width="2px" height="12px">
SWAM / SWIF<br>
</div>
...
A snipped of my code is:
try:
res = driver.find_elements_by_link_text('PInt')
print("res1:{}".format(res))
res = driver.find_element(By.XPATH,'//*[#id="submenu1"]/a[3]')
print("res:{} type[0]:{}".format(res,res[0]))
itm1 = res[0]
itm1.click()
I get the error:
Unable to locate element:
{"method":"xpath","selector":"//*[#id="submenu1"]/a[2]"}
My question is, how can I get the right xPath of the element or any other way to access the element?
UPDATE:
This might be important, the issue with
Message: invalid selector: Unable to locate an element with the xpath expression (and I've tried all proposed solutions) might be that this is after authenticate in the webpage (User + Pwd) before, everything works.
I noticed that the url driver.current_url after login is static (asp page).
Also this part I am trying to access in a frameset and frame
html > frameset > frameset > frame:nth-child(1)
Thanks to #JeffC to point me in the right direction.
since the page has some frames, I manage to access the element first by switching to the right frame (using xPath)
and then access the element.
driver.switch_to.default_content()
driver.switch_to.frame(driver.find_element_by_xpath('html / frameset / frameset / frame[1]'))
driver.find_element_by_xpath("//a[contains(text(),'PInt')]").click()
BTW, in case you want to run the script from a crontab,you need to setup a display:
30 5 * * * export DISPLAY=:0; python /usr/.../main.py
To see a full list of all the ways of selecting elements using selenium, you can read all about it in the documentation.
Using xpath:
res = driver.find_element_by_xpath(u'//*[#id="submenu1"]/a[2]')
Using css selector:
res = driver.find_element_by_css_selector('#submenu1 a:nth-of-type(2)')
Try with any of the below xpath. Sometimes automatically generated xpath does not work.
//a[contains(text(),'PInt')]
or
//div[#id='submenu1']//a[contains(text(),'PInt')]
Also I would suggest you to set some wait time before clicking on above link in case if above xpath does not work
To find xPath in chrome:
Right click the element you want
Inspect, which will open the developer window and highlight the selected element.
Right click the highlighted element and choose copy > copy by xpath
Here is a list of all the different ways to locate an element Locating Elements

Categories

Resources