I am using selenium in python and cannot get it to find and select the ok button. Here is the code I am trying to use that is not finding the button.
SubmitElem = driver.find_element_by_name('ctl00$PlaceHolderMain$ctl01$RptControls$btnOK')
SubmitElem.submit()
And this is the webpage code
<input name="ctl00$PlaceHolderMain$ctl01$RptControls$btnOK"
value="OK"
onclick="javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions("ctl00$PlaceHolderMain$ctl01$RptControls$btnOK", "", true, "", "", false, false))"
id="ctl00_PlaceHolderMain_ctl01_RptControls_btnOK" accesskey="o"
class="ms-ButtonHeightWidth" type="submit">
Any advice on what I am doing wrong? I found some suggestions to add onclick*= but it did not seem to work.
As noted earlier, if the element is in an iframe, you need to switch contexts. Additionally, if the element takes time to show up on the DOM, due to it being dynamically rendered by JavaScript, you might need waits. You basically want to wait until the element shows up on the page before performing actions on it.
From the Selenium docs:
element = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.ID, "myDynamicElement"))
)
Here is the Answer to your Question:
As per the HTML you have provided, you may consider the following options:
You can consider to construct a xpath based on name as follows:
SubmitElem = driver.find_element_by_xpath("//input[#name='ctl00$PlaceHolderMain$ctl01$RptControls$btnOK']")
SubmitElem.submit()
You can also try a different xpath based on id as follows:
SubmitElem = driver.find_element_by_xpath("//input[#id='ctl00_PlaceHolderMain_ctl01_RptControls_btnOK']")
SubmitElem.submit()
Alternatively, you can also consider to call click() method instead of submit() method.
SubmitElem.click()
Again, it seems to me that the id and name is dynamic due to presence of JavaScript and AJAX Calls. In that case you can consider to construct a dynamic xpath as follows:
SubmitElem = driver.find_element_by_xpath("//input[starts-with(#id, 'ctl00')]")
SubmitElem.submit()
You can consider to construct a dynamic css_selector as follows:
SubmitElem = driver.find_element_by_css_selector("input[id^='ctl00']")
SubmitElem.submit()
Finally, if you see a NoSuchElementException or ElementNotVisibleException you may consider to induce some WebDriverWait as follows:
WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.XPATH, "//input[starts-with(#name, 'ctl00')]")))
driver.find_element_by_css_selector("input[name^='ctl00']").click()
There are total 6 suggested locators to identify the element along with different other options.
Let me know if this Answers your Question.
Related
Im trying to perform select and click action from the search box result dropdown for testing purpose. Though i dont get ant error but i'm stuck and not able to do so, search results came then disappeared immediately. Please any one help me out. Im using Python script to automate webdriver. Here is the screenshot below for reference.
. I have tried webdriverwait for same action but it gives Timeout exception error. If there is any child actions from CSS to perform let me know. Here is what i tried
search = driver.find_element_by_id('searchInput')
search.send_keys("flowers")
dropdown = WebDriverWait(driver, 4).until(
EC.presence_of_element_located((By.XPATH, "//li[text()='flowers']")))
Apart from this snippet, i want to rather just perform enter key operation, where i get query result for 'flower' on this ecomm. website.
Here is the website URL- https://paytmmall.com
Once you type flower in the input field, there are multiple options appearing based on the input provided. They are in li tags and under b tag.
Code :
driver = webdriver.Chrome(driver_path)
driver.maximize_window()
#driver.implicitly_wait(30)
wait = WebDriverWait(driver, 30)
driver.get("https://paytmmall.com/")
search = wait.until(EC.visibility_of_element_located((By.ID, "searchInput")))
search.send_keys("flowers")
time.sleep(3)
wait.until(EC.visibility_of_element_located((By.XPATH, "(//li)[4]/descendant::b[contains(text(),'flowers')]"))).click()
time.sleep is just for visibility purpose. you can remove that as well.
Also this xpath (//li)[4]/descendant::b[contains(text(),'flowers')] is based on xpath indexing , since I think you wanna select the 4th option which is flower itself. In case you wanna select a different option, you would have to write the different xpath.
In case you are looking to just select the searched item, it's better to pass enter key once you type flower in the input field.
You can use the below code for that :
search = wait.until(EC.visibility_of_element_located((By.ID, "searchInput")))
search.send_keys("flowers")
time.sleep(3)
search.send_keys(Keys.RETURN)
The suggested options are not containing the text directly in li elements, they are inside child elements inside li elements.
Try this instead:
search = driver.find_element_by_id('searchInput')
search.send_keys("flowers")
dropdown = WebDriverWait(driver, 4).until(
EC.visibility_of_element_located((By.XPATH, "//li//*[text()='flowers']")))
I am trying to get Selenium to do a Youtube search for me and I got to the final step which is actually entering the text and I'm stuck. searchElem uses the id that allows me to use .click(), but I cannot use send_keys() with that id so I tried inputElem and that doesn't work either.
There isn't a more specific id or class to use for the search input so I'm not sure what to do.
Below is the error I get once I try to use send_keys() with searchElem and inputElem.
selenium.common.exceptions.ElementNotInteractableException: Message: Element <div id="search-input" class="ytd-searchbox-spt"> is not reachable by keyboard
This is my code for the WebDriver and elements within the source code.
driver = webdriver.Firefox()
driver.get('https://www.youtube.com')
searchElem = driver.find_element_by_id('search-input')
inputElem = driver.find_element_by_id('search')
searchElem.click()
searchElem.send_keys('election')
It's possible that 'search' is the ID of a different element that is being picked up, so try using the xpath instead.
inputElem = browser.find_element_by_xpath('/html/body/ytd-app/div/div/ytd-masthead/div[3]/div[2]/ytd-searchbox/form/div/div[1]/input')
inputElem.send_keys('election')
You can create the locator based on search field placeholder (this would make it unique)
For example, for english, the placeholder would be "Search" and your locator would look like:
//input[#placeholder='Search']
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
Ive been using selenium to scrape a site to retrieve some information.
the information is hidden behind a see more tab that is being revealed using javascript when i click it. I have tried many different methods to get the the information visible. and it does not seem to be working .
I have tried to use action chains along with the regular xpath methods to chain the functionality together but it still does not seem to be clicking all the other info is pulled and the button text is printed out to the console instead of being clicked.
def grabDetails(self):
facts = self.browser.find_elements_by_xpath("//section[#id='hdp-content']/main/div/div[4]")
for fact in facts:
details = fact.text
print(details)
def moreFeatures(self):
view_more_elements = WebDriverWait(self.browser, 20).until(EC.visibility_of_element_located((By.XPATH, "//a[contains(text(),'See More Facts and Features')]")))
# features.click()
ActionChains(view_more_elements).double_click().preform()
# self.browser.execute_script('arguments[0].scrollIntoView(true);', features)
Im trying to get the information from this page printed out !
here is the zillow page that im trying to scrape
its the see more sections part below it
You are setting view_more_elements as a WebDriverWait object rather than a WebElement. This will prevent the object from being clickable. You just need to run WebDriverWait as it's own call, then .click() the element.
view_more_xpath = '//div[#class="read-more zsg-centered"]/a'
view_more_elements = WebDriverWait(self.browser, 20).until(EC.visibility_of_element_located((By.XPATH, view_more_xpath))
self.browser.find_element_by_xpath(view_more_xpath).click()
EDIT: you don't actually need to set WebDriverWait to view_more_elements. You can just do:
view_more_xpath = '//div[#class="read-more zsg-centered"]/a'
WebDriverWait(self.browser, 20).until(EC.visibility_of_element_located((By.XPATH, view_more_xpath))
self.browser.find_element_by_xpath(view_more_xpath).click()
I recently recommended to my devs to add IDs to each element on the project I'm working to make automation more robust, they added in aria-uuid to each element. I cannot get anything to recognize these IDs! I'm wondering if it is even possible?
I'm using python/selenium.
I've tried identifying elements by ID, I've done CSS selectors and xpaths but they have had a history of breaking between new builds.
Relevant html:
input class="short ng-valid ng-not-empty ng-valid-min ng-valid-required" name="question_16" type="number" aria-uuid="question_16_input" ng-required="true" ng-min="0" ng-model="$ctrl.vault['question_16'].value"
def click_element_by_id(self, driver_init, id1, message1, delay1, halt):
try:
element = WebDriverWait(driver_init, delay1).until(EC.element_to_be_clickable((By.ID, id1)))
element.click()
except TimeoutException:
if halt:
assert_that(True, message1).is_false()
else:
print(message1)
Each time I get the assertion/timeout error
Ideally, yes you should have been able to recognize each individual elements with respect to their aria-uuid to be used with Selenium provided the generated aria-uuid were static.
As per the HTML you have shared the generated aria-uuid seems to be dynamic. So aria-uuid alone won't help you. In these cases you have to use the aria-uuid along with the other attributes to uniquely identify the elements. To identify this element you can use either of the following Locator Strategies:
Using CSS_SELECTOR:
WebDriverWait(driver_init, delay1).until(EC.element_to_be_clickable((By.CSS_SELECTOR, "input.short.ng-valid.ng-not-empty.ng-valid-min.ng-valid-required[aria-uuid$='_input'][name^='question_']"))).click()
Using XPATH:
WebDriverWait(driver_init, delay1).until(EC.element_to_be_clickable((By.XPATH, "//input[#class='short ng-valid ng-not-empty ng-valid-min ng-valid-required' and contains(#aria-uuid, '_input')][starts-with(#name, 'question_')]"))).click()
It should be possible with a CSS selector [aria-uuid='question_16_input']