I am working on this automation thing and I am trying to click on this button with selector
<button id="ember2570" class="ember-view btn btn-default btn btn-default" type="button"> <i class="fa fa-upload"></i>
PDMLink<!----></button>
I have tried find_element_by_id but the ID changes with every reload and the class names are also not unique to the button.
if I try including wildcard like "ember*" then it clicks somewhere else. Almost all the elements of the web page has id="embersomeRandomNumber"
I cannot share the url as it is an intranet site.
Using CSS Selector:
The Operator ^ - Match element that starts with the given value.
In your case:
driver.find_element_by_css_selector('button[id^="ember"] i.fa-upload')
Using XPath:
The keyword contains Match element that contains the given value.
driver.find_element_by_xpath("//button[contains(#id,'ember')/i[contains(#class,'fa-upload')]")
Edit:
If you are looking for the button with the text of "PDMLink":
You can use text in the XPath:
driver.find_element_by_xpath("//button[text()='PDMLink']")
So here is how i would approach this simple "problem":
driver.find_element_by_css_selector("button[id^="ember"] i.fa-upload").click()
If click doesnt work, then you can also import keys and do .send_keys(Keys.RETURN)
I havent worked with selenium in quite a bit so give that a try and let me know.
I usually work with my own API i built last year which has functions like type(), find(), find_path(), find_id(), click() and all of them are built to avoid capcha cashe from building and avoiding most of those "im not a robot" things which crash bots. I just use time delays at random intervals. The type() actually recieves the string and types char by char on a small time delay which is always random and that is the main thing
As you have mentioned ...the ID changes with every reload and the class names are also not unique to the button... additionally the desired element is a Ember.js enabled element so to click() on the element you have to induce WebDriverWait for the element_to_be_clickable() and you can use the following Locator Strategy:
Using XPATH:
WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, "//button[#class='ember-view btn btn-default btn btn-default' and contains(., 'PDMLink')][.//i[#class='fa fa-upload']]"))).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
Related
Normally a picture is gladly displayed via an ID. But in my example these images are displayed as content / character:
.fa-calendar-alt:before {
Synchro : "\f073";
What can I do here?
If I understood you correctly, you need to ckeck the "content" value of before pseudo-element.
In this case I'd suggest you to try to do it with JS. Look here to see how to run JS code via selenium.
return document.defaultView.getComputedStyle(document.querySelector('.far.fa-calendar-alt'), ':before')['content'];
After getting the value you can do simple string comparison.
check for the class name if it exists then execute your next step.
e.g. driver.find_element_by_class_name("far fa-calendar-alt")
or you can just define it's xpath. Let me know if you need to know how to find the xpath.
Edit: Xpath example:
//div//i[#class="far fa-calendar-alt"]
A bit of more details about your usecase would have helped us to construct a more canonical answer. However, the desired element is applied with a A CSS pseudo-element.
Usually the Calendar elements are interactive. So to identify the Calendar element you need to induce WebDriverWait for the element_to_be_clickable() and you can use either of the following Locator Strategies:
Using CSS_SELECTOR:
calendar = WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.CSS_SELECTOR, "i.far.fa-calendar-alt")))
Using XPATH:
calendar = WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.XPATH, "//i[#class='far fa-calendar-alt']")))
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
CSS Pseudo-elements
Now, if your usecase is to extract the value of the content property of the ::before element i.e. Synchro : "\f073" you can use the following solution:
script = "return window.getComputedStyle(document.querySelector('.fa-calendar-alt'),':before').getPropertyValue('content')"
print(driver.execute_script(script).strip())
Reference
You can find a detailed discussion in:
How locate the pseudo-element ::before using Selenium Python
There are two things here. Your code is font-awesome library. And the calendar icon is suppose to use the class fa-calendar-alt.
Now if you expect your icon to be a calendar, just checking if the class fa-calendar-alt exists on your element should be good enough to check if the calendar icon will appear.
Once this class is there you can assume that the calendar icon will be displayed. Now the other assumption that we make is that the font-awesome library was actually included by the html, because if for some reason the library is not included then even though class of calendar is correct, the icon will still not load. So for that you can check if a given class actually exists in CSS or not. Below thread can help you for the same
How can you determine if a css class exists with Javascript?
I would never worry about checking this, because chances of such occurrences will always be very low.
I would discourage checking content values of the class itself, as you are then making it implementation dependent, which you shouldn't. Like in Font Awesome 5.0, it use SVG to do all this instead of a font
I'm playing around with a mini-challenge that's been set to automate a form response on survey monkey, I've set up a dummy survey for the purpose of this example.
Essentially, selenium is unable to click the box due to an error with a button display obscuring it.
ElementClickInterceptedException: Message: Element input id="234136539_1601280849" class="checkbox-button-input " name="234136539[]" type="checkbox"> is not clickable at point (237.5,345.5) because another element span class="checkbox-button-display "> obscures it
I've looked at this question which is Java specific, and I can't quite get my head around how I go about getting past this, I've tried implicit waits, clicking on the box around it but a little lost where to begin without learning Java.
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
driver = webdriver.Firefox()
driver.get('https://www.surveymonkey.com/r/L9DJGXR')
vote_check = driver.find_element_by_id('234136539_1601280849')
vote_check.click()
This code should replicate the problem with the dummy survey.
Right-click on the checkbox next to "Me" and choose Inspect... what element is selected? The SPAN. That's because the SPAN overlaps the INPUT you want to click. That's what that error is telling you. You are trying to click on an element that is covered by another element. Selenium can't "see" the page to see that the element underneath is not really obscured.
The solution is to click either the SPAN that was in the error or the LABEL. It doesn't really matter which you do, both will work. Two CSS selectors are below
[id='234136539_1601280849'] + label // clicks the LABEL
^ has this ID
^ '+' means sibling
^ LABEL tag
[id='234136539_1601280849'] + label > span // clicks the SPAN
everything is the same as above until...
^ '>' means child
^ SPAN tag
To click the second check box associated with text Me you have to induce WebDriverWait for the element to be clickable and you can use the following solution:
Code Block:
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
driver = webdriver.Firefox(executable_path=r'C:\Utility\BrowserDrivers\geckodriver.exe')
driver.get('https://www.surveymonkey.com/r/L9DJGXR')
WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, "//div[#class='question-body clearfix notranslate ']//following::label[2]"))).click()
Browser Snapshot:
I am automating a function where the user needs to click on the link highlighted in the below link.
HTML
I tried a contains on the xpath which is //*[#id="lc"], and an onclick option from Here neither of which work and error with the element doesn't exist error.
I know I am in the right iframe, because when using the xpath with no contains the script clicks the first xpath link with no issue.
To click() on the desired element as the element is a dynamic element you have to induce WebDriverWait for the element to be clickable and you can use either of the following Locator Strategies:
Using CSS_SELECTOR:
WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.CSS_SELECTOR, "td.EMROtherEpsEven>table tr>td.EMROtherEpsEven#lc[onclick*='Hemoglobin']"))).click()
Using XPATH:
WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, "//td[#class='EMROtherEpsEven']/table//tr/td[#class='EMROtherEpsEven' and #id='lc'][contains(#onclick, 'Hemoglobin')]"))).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
I have not use Selenium with Python, but I have with java, and in Java you have to use simple quote (') instead the double quote ("), or you can just a simpler locator id=lc without any quotes, if you're sure the ID is correct this should work.
i have done this in java hope you find the answer
yes in static or in dynamic tables the id will be the same but if you try using absolute xpath
this are two absolute path of the table element resides each other in first row
/html[1]/body[1]/section[1]/section[1]/div[1]/data[1]/div[1]/div[4]/div[1]/div[1]/div[1]/div[1]/div[2]/div[2]/div[1]/div[1]/div[1]/div[1]
/html[1]/body[1]/section[1]/section[1]/div[1]/data[1]/div[1]/div[4]/div[1]/div[1]/div[1]/div[1]/div[2]/div[2]/div[1]/div[1]/div[1]/div[2]/div[1]
This are the relative xpath of the same elements
//a[contains(text(),'AF17OT41603')]
//div[#id='1547533504703-0-uiGrid-000C-cell']//div[#class='ui-grid-cell-contents ng-binding ng-scope'][contains(text(),'AKSHAY PATIL')]
Table
On the website, the input tag is this:
<input value="Submit" type="submit">
How can I make selenium select this input button?
I tried this:
browser.find_element_by_css_selector("input[value='submit']")
But it wasn't able to find the input button.
I would use this xpath to find the above input:
browser.find_element_by_xpath(".//input[#value='Submit' and #type='submit']")
If there are multiple inputs with the same attributes, you may need to find by index as well.
UPDATE:
Since you are having trouble finding the element, and there are no iframes on the page, I would suggest using WebDriverWait in case there are any AJAX/JavaScript/Dynamic load events that are creating the input after the pageload is complete.
Import these into your script:
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
Then try this:
wait = WebDriverWait(browser, 10)
wait.until(EC.element_to_be_clickable((By.XPATH, ".//input[#value='Submit' and #type='submit']"))).click()
As mentioned in your comment, you had to switch to a new tab. The way to do this in Selenium is:
#this will switch to the newest tab
browser.switch_to_window(browser.window_handles[-1])
Please make sure that input tag is in the an iframe?
if it in an iframe you should use
browser.switch_to.frame('iframe's id') to enter the iframe, if you enter this frame, you can use xpath or css selector to find the tag you want.
There's a clear mispelling, the 'Submit' value has a capitalised S in your sourcecode, but you have provided lowercase in your selector. Try this instead!
browser.find_element_by_css_selector("input[value='Submit']")
I am dealing with a situation where every time I login a report is displayed in a table whose ID is dynamically generated with random text ending with "table".
I am automating this table with selenium python web driver. It has Syntax
driver.find_element_by_xpath('//*[#id="isc_43table"]/tbody/tr[1]/td[11]').click();
help me editing this syntax to match it with table ending id with "table".
(only one table is generated).
The ends-with XPath Constraint Function is part of XPath v2.0 but as per the current implementation Selenium supports XPath v1.0.
As per the HTML you have shared to identify the element you can use either of the Locator Strategies:
XPath using contains():
driver.find_element_by_xpath("//*[contains(#id,'table')]/tbody/tr[1]/td[11]").click();
Further, as you have mentioned that table whose ID is dynamically generated so to invoke click() on the desired element you need to induce WebDriverWait for the element to be clickable and you can use the following solution:
WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, "//*[contains(#id,'table')]/tbody/tr[1]/td[11]"))).click()
Alternatively, you can also use CssSelector as:
driver.find_element_by_css_selector("[id$='table']>tbody>tr>td:nth-of-type(11)").click();
Again, you can also use CssSelector inducing WebDriverWait as:
WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.CSS_SELECTOR, "[id$='table']>tbody>tr>td:nth-of-type(11)"))).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
I hope, either these 2 will work for you
driver.find_element_by_xpath("//table[ends-with(#id,'table')]/tbody/tr[1]/td[11]").click();
OR
driver.find_element_by_xpath("//table[substring(#id,'table')]/tbody/tr[1]/td[11]").click();
If not getting, remove the tags from tbody.
For such situations, when you face randomly generated ids, you can use the below functions with XPATH expression
1) Contains,
2) Starts-with &
3) Ends-with
4) substring
Syntax
//table[ends-with(#id,'table')]
//h4/a[contains(text(),'SAP M')]
//div[substring(#id,'table')]
You need to identify the element which is having that id, whether its div or input or table. I think its a table.
You can try below XPath to simulate ends-with() syntax:
'//table[substring(#id, string-length(#id) - string-length("table") +1) = "table"]//tr[1]/td[11]'
You can also use CSS selector:
'table[id$="table"] tr>td:nth-of-type(11)'