from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support import expected_conditions as EC
import os
Game_Pin = input('Enter your PIN: ')
NickNAME = input('Enter your nickname: ')
driver = webdriver.Chrome(executable_path=r"C:\WebDriver\bin\chromedriver.exe")
def Enter_Press(driver):
driver.find_element_by_xpath("//*[contains(text(), 'Enter')]").click()
def OK_GO(driver):
driver.find_element_by_xpath("//*[#class='btn btn-greyscale join ng-binding']").click()
def Kahoot_Spammer(Game_Pin, NickNAME, driver):
driver.get('https://kahoot.it/')
driver.maximize_window() #For maximizing window
driver.implicitly_wait(2) #gives an implicit wait for 2 seconds
game_pin = driver.find_element_by_xpath("//*[#id='inputSession']")
game_pin.send_keys(Game_Pin)
Enter_Press(driver)
driver.implicitly_wait(2)
Name = driver.find_element_by_xpath("//*[#id='username']")
Name.send_keys(NickNAME)
OK_GO(driver)
Kahoot_Spammer(Game_Pin, NickNAME, driver)
The program works fine until you get to a certain point. Then selenium cannot click a button. It gives me this error.
selenium.common.exceptions.WebDriverException: Message: unknown error: Element <button type="submit" class="btn btn-greyscale join ng-binding" blocking="" data-functional-selector="join-button-username">...</button> is not clickable at point (1279, 741). Other element would receive the click: <div id="waitOverlay" class="alert-fullscreen valignwrapper" data-functional-selector="wait-overlay" style="opacity: 0.7;">...</div>
Here is the code for the button I am trying to click.
<button class="btn btn-greyscale join ng-binding" type="submit" data-functional-selector="join-button-username" blocking=""> OK, go! </button>
You can use action class to resolve this exception,
action=ActionChains(driver)
action.move_to_element("Your element").click().build().perform()
You use implicitly_wait as a wrong way. In selenium implicitly wait is for setting the find duration of all selenium find API, like find_element_by_xxx. Rather than used for waiting page refresh/load complete.
From the error message we can know, when you click on the Go button, but another element (A layer display loading which at top of the GO button ) received the click event.
So you need to wait the loading layer disappear before click anything covered by it.
Enter_Press(driver)
// driver.implicitly_wait(2)
// remove above 'implicitly_wait' line,
// you set the find duration to 2 seconds, the default value is 10 seconds.
// we don't recommend to change this default value, unless you are doing
// performance testing to expect the element comes out on page in short time.
// Selenium will return the find result once it found before 10 seconds,
// otherwise throw `NoSuchElementException` if exceed 10 seconds.
diver.wait(xxx) // or simply use sleep() to wait the `loading` disappear.
Name = driver.find_element_by_xpath("//*[#id='username']")
Name.send_keys(NickNAME)
OK_GO(driver)
Related
I'm using Selenium Webdriver to check a box in a form and click save on the same page. The checkbox works fine, but cannot click save. I have tried multiple solutions without a working solution. I add a sleep as after clicking save manually it does take a while to process.
Here is the html for the save button:
<input class="cbi-button cbi-button-apply" type="submit" name="cbi.apply" value="Save">
Here is my code using xpath (attempt 1):
driver.find_element_by_xpath("//input[#type='submit']").click()
time.sleep(20)
Output from attempt 1:
ElementNotInteractableException: Message: element not interactable
Attempt 2 using action chains as suggested by another answer:
button = driver.find_element_by_class_name(u"cbi-page-actions")
driver.implicitly_wait(10)
ActionChains(driver).move_to_element(button).click(button).perform()
time.sleep(20)
There are no errors raised in this second attempt but from watching the browser the save button did not seem to be clicked. I have also checked afterwards on the page and the changes I added were definitely not saved.
I've also attempted using webforms however I have the opposite problem where I am able to save the form but cannot select the checkbox.
Try this
element = driver.find_element_by_xpath("//input[#type='submit']")
driver.execute_script("arguments[0].click();", element)
You should wait before, may be the element was not loaded properly, not after triggering the click
Solution 1: Direct click with worst type of Explicit wait
time.sleep(20)
driver.find_element_by_xpath("//input[#type='submit']").click()
Solution 2: Using Actions chain :
button = driver.find_element_by_css_selector("input[value='Save']")
ActionChains(driver).move_to_element(button).click(button).perform()
Solution 3: Using dynamic Explicit wait:-
wait = WebDriverWait(driver, 20)
wait.until(EC.element_to_be_clickable((By.NAME, "cbi.apply"))).click()
Imports :
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
Solution 4: Using Js
button = driver.find_element_by_name("cbi.apply")
driver.execute_script("arguments[0].click();", button)
I have tried to make my script click the Purchase/Buy Family button on the Spotify Checkout Page. No matter what class, CSS, XPath, ID, or whatever I put in, it's just saying it could not find the object.
This is the button. It's not in an iframe:
<div class="sc-fzXfOu cvoJMt">
<button id="checkout_submit" class="Button-oyfj48-0 kaOWUo sc-fzXfOv tSdMK">
Buy Premium Family
</button>
</div>
My code:
time.sleep(3)
buy = driver.find_element_by_xpath("/html/body/div[3]/div/div/div/div/div/div/div[3]/div/div/div[2]/form/div[2]/button").click()
I am able to click the button,by a different xpath
driver.findElement(By.xpath("//button[#id='checkout_submit']")).click();
Edit -
Your xpath also works for me only when i load the page initially and there is no change in the dom - /html/body/div[3]/div/div/div/div/div/div/div[3]/div/div/div[2]/form/div[2]/button
It doesn't work when some new event or error is displayed and the dom structure changes.
Why use such relative XPath when the element has distinguishable attributes?
The problem here is the form is not static you have to wait loading of all elements.
And page loads with pane to accept cookies who can mask elements you want to run action on.
The best way in that case is first accept cookies and then run all actions you need.
Try to adapt this code for your needs, that run with success on my test.
In case you run this code you have to brake execution to login first, when the driver get the page.
from selenium import webdriver
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.remote.webelement import WebElement
# change this line
path_driver = "your_path_to_chrome_driver"
by, buy_selector, cookies_selector = By.CSS_SELECTOR, 'button#checkout_submit', "button#onetrust-accept-btn-handler"
driver = webdriver.Chrome(path_driver)
driver.maximize_window()
actions = ActionChains(driver)
driver.get("https://www.spotify.com/us/purchase/offer/premium-family/?country=US")
# wait for loading buy button
sls = wait.until(EC.presence_of_all_elements_located((by, buy_selector)))
if sls:
# get accept cookies button element and click
cookies_accept = driver.find_element_by_css_selector(cookies_selector)
if isinstance(cookies_accept, WebElement):
cookies_accept.click()
# get buy button element, move to element and click
buy = driver.find_element_by_css_selector(buy_selector)
if isinstance(buy, WebElement) and buy.is_displayed() and buy.is_enabled():
actions.move_to_element(buy).click(buy).perform()
I've written a script in python in combination with selenium to log in to a website. The thing is my script sometimes successfully gets logged in but most of the times it comes across a slider which is meant to press and slide to the right.
Website link
Image of that slider:
How can I let my script slide that button to the right?
I've tried with:
from selenium import webdriver
from selenium.webdriver import ActionChains
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
def sign_in():
driver.get("https://login.aliexpress.com/")
wait.until(EC.frame_to_be_available_and_switch_to_it(wait.until(EC.visibility_of_element_located((By.CSS_SELECTOR, "#alibaba-login-box")))))
wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, "input#fm-login-id"))).send_keys("someEmail")
wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, "input#fm-login-password"))).send_keys("somePassword")
wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, "button[class$='password-login']"))).click()
#the following line is for handling the slider but it doesn't do anything
item = wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, ".nc_wrapper .btn_slide")))
ActionChains(driver).move_to_element(item).perform()
if __name__ == '__main__':
driver = webdriver.Chrome()
wait = WebDriverWait(driver,10)
sign_in()
Html elements connected to that slider:
<div id="nc_1_n1t" class="nc_scale">
<div id="nc_1__bg" class="nc_bg" style="width: 0px;"></div>
<span id="nc_1_n1z" class="nc_iconfont btn_slide" data-spm-anchor-id="0.0.0.i1.3f9579f4qCwuHp" style="left: 0px;"></span>
<div id="nc_1__scale_text" class="scale_text slidetounlock"><span class="nc-lang-cnt" data-nc-lang="_startTEXT">Please slide to verify</span></div>
<div id="nc_1_clickCaptcha" class="clickCaptcha" style="top: -118px; height: 235px;">
<div class="clickCaptcha_text">
<b id="nc_1__captcha_text" class="nc_captch_text"></b>
<i id="nc_1__btn_2" class="nc_iconfont nc_btn_2 btn_refresh"></i>
</div>
<div class="clickCaptcha_img"></div>
<div class="clickCaptcha_btn"></div>
</div>
<div id="nc_1_imgCaptcha" class="imgCaptcha" style="top: -118px; min-height: 290px; height: 189px;">
<div class="imgCaptcha_text"><input id="nc_1_captcha_input" maxlength="6" type="text" style="ime-mode:disabled"></div>
<div class="imgCaptcha_img" id="nc_1__imgCaptcha_img"></div>
<i id="nc_1__btn_1" class="nc_iconfont nc_btn_1 btn_refresh" onclick="document.getElementById('nc_1__imgCaptcha_img').children[0].click()"></i>
<div class="imgCaptcha_btn">
<div id="nc_1__captcha_img_text" class="nc_captcha_img_text"></div>
<div id="nc_1_scale_submit" class="nc_scale_submit"></div>
</div>
</div>
<div id="nc_1_cc" class="nc-cc"></div>
<i id="nc_1__voicebtn" tabindex="0" role="button" class="nc_voicebtn nc_iconfont" style="display:none"></i>
<b id="nc_1__helpbtn" class="nc_helpbtn"><span class="nc-lang-cnt" data-nc-lang="_learning">help</span></b>
</div>
I'm unable to get the slider to display on the website linked in the question, so I have provided a solution using another site that has a slider element (I'm assuming the functionality is similar to the one on the aliexpress website).
from selenium import webdriver
from selenium.webdriver import ActionChains
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
# Instantiate objects
driver = webdriver.Chrome()
actions = ActionChains(driver)
# Load page and fill in input elements
driver.get("http://kthornbloom.com/slidetosubmit/")
driver.find_element(By.NAME, "name").send_keys("Fred")
driver.find_element(By.NAME, "email").send_keys("fred#example.com")
# Find slider elements
slider_container = driver.find_element(By.CSS_SELECTOR, ".slide-submit")
slider = driver.find_element(By.CSS_SELECTOR, ".slide-submit-thumb")
# Perform sliding action
actions.move_to_element(slider).click_and_hold().move_by_offset(slider_container.size['width'], 0).release().perform()
# Browser intentionally left open so that you can see what happened when the test was run!
The key part here, is the Perform sliding action line. We have to identify two specific elements:
The element that we are going to slide
The container that holds this element
Once we have found both of these elements, we use the actions class to click and hold the element we need to slide and then we slide it the width of the containing element along the x axis (as shown using slider_container.size['width']), without changing the y axis.
This should fix your sliding problem, however you will have another problem, you need to work out if the slider was displayed, or you were logged into the website. To do that you are going to need an Expected condition that checks for the existence of 2 elements:
The slider.
An element you would expect to see when you have successfully logged in.
If the element you would expect to see when you log in is shown, you don't need to do anything. If the slider is shown, you will need to perform the above logic to slide the bar across.
*Edit*
To improve on this a bit more you can put the sliding code into an ExpectedCondition like so:
class wait_for_element_while_verifying_slider(object):
def __init__(self, locator, slider_container_locator, slider_locator):
self.locator = locator
self.slider_container_locator = slider_container_locator
self.slider_locator = slider_locator
def __call__(self, _driver):
try:
return _driver.find_element(*self.locator)
except (NoSuchElementException, StaleElementReferenceException):
container = _driver.find_elements(*self.slider_container_locator)
slider = _driver.find_elements(*self.slider_locator)
if len(container) > 0 and len(slider) > 0:
actions = ActionChains(_driver)
actions.move_to_element(slider[0]).click_and_hold().move_by_offset(container[0].size['width'], 0).release().perform()
return False
This will search for an element that you expect to be shown when you log in. If the element that you would expect to see when you have successfully logged in is not shown, it will then try and locate the slider elements and interact with them to process the slide verification. Note that once it tries to perform the slide verification the Expected Condition will return False which will force it to check to see if the expected logged in element is displayed again.
You can use it in your code like this:
# Instantiate objects
driver = webdriver.Chrome()
wait = WebDriverWait(driver, 10)
# Load page and fill in input elements
driver.get("http://kthornbloom.com/slidetosubmit/")
driver.find_element(By.NAME, "name").send_keys("Fred")
driver.find_element(By.NAME, "email").send_keys("fred#example.com")
# Define slider elements and element that will be shown when you successfully log in
SLIDER_CONTAINER = (By.CSS_SELECTOR, ".slide-submit")
SLIDER = (By.CSS_SELECTOR, ".slide-submit-thumb")
ELEMENT_TO_FIND = (By.XPATH, "//div[.=\"Looks Like You're Human!\"]")
# Invoke the explicit wait that will deal with the slider if it is displayed
wait.until(wait_for_element_while_verifying_slider(ELEMENT_TO_FIND, SLIDER_CONTAINER, SLIDER))
The example above uses the same example website as above. To make it timeout you can change ELEMENT_TO_FIND to something that doesn't exist. To make it pass without sliding you can modify ELEMENT_TO_FIND to be:
ELEMENT_TO_FIND = (By.XPATH, "//div[.=\"Slide To Submit\"]")
Using the code you have provided in your comment I would expect the following to work on the aliexpress website:
# Define slider elements and element that will be shown when you successfully log in
SLIDER_CONTAINER = (By.CSS_SELECTOR, ".nc-lang-cnt")
SLIDER = (By.CSS_SELECTOR, ".nc_wrapper .btn_slide")
ELEMENT_TO_FIND = (By.ID, "search-key")
# Invoke the explicit wait that will deal with the slider if it is displayed
wait.until(wait_for_element_while_verifying_slider(ELEMENT_TO_FIND, SLIDER_CONTAINER, SLIDER))
Try using Actions Below is c# code for reference
//following code will click and hold the slider
string Xpath=""; //set xpath for desired element to be click and hold
Actions clickHold = new Actions(driver);
IWebElement element = driver.FindElement(By.XPath(Xpath));
clickHold.ClickAndHold(element).Perform();
once you have held on slider try to move it to the desired offset value
int x = 100;
int y = 100;
Actions moveOffset = new Actions(driver);
moveOffset.MoveByOffset(x,y).Perform(); //set your suitable (x,y) offset value
The sample code (in java) for slider operation from left to right is below.
Actions slider=new Actions(driver);
slider.clickAndHold("xpath of slider");
slider.movebyoffset(x,y).build.perform();
in place of 'x' &'y' you can give actual offset value as per your application.
I'm trying to fill out a form on a website that has different versions depending on language, location, etc. I am using the same firefox profile for every request, and the previously selected information is stored locally in cookies, so after choosing a setting the first time, the modal doesn't appear for a while. However: it seems to inconsistently appear, taking focus away from the form and causing an ElementNotInteractableException.
To add more difficulty, the modal will often appear some time after the page has loaded. For example, the first field will already be filled out, and then it appears.
My question is, what is the best way to handle this modal? Can I catch the exception cause by its appearance, check for the presence of the modal, and then continue populating the form fields? Or is there a better solution?
Thanks for any help.
The code I have tried so far:
url = "https://www.aircanada.com/ca/en/aco/home.html"
control_profile = webdriver.FirefoxProfile('/path/to/my/profile')
browser_control = webdriver.Firefox(control_profile)
browser_control.get(url)
# To deal with the modal, but obviously fails when it is not present
browser_control.find_element_by_id('enCAEdition').click()
# two text fields I tried to fill out, as a sanity check
departure = browser_control.find_element_by_id('origin_focus_0')
departure.send_keys("my departure location")
departure.send_keys(Keys.RETURN)
destination = browser_control.find_element_by_id('destination_label_0')
destination.send_keys("my destination")
destination.send_keys(Keys.RETURN)
You can wait some time until modal appears, close it and handle form:
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait as wait
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import TimeoutException
url = "https://www.aircanada.com/ca/en/aco/home.html"
control_profile = webdriver.FirefoxProfile('/path/to/my/profile')
browser_control = webdriver.Firefox(control_profile)
browser_control.get(url)
# Wait up to 10 seconds until modal appears to close it
try:
wait(browser_control, 10).until(EC.element_to_be_clickable(('xpath', '//button[text()="Confirm | Confirmer"]'))).click()
# If modal didn't appear- just continue
except TimeoutException:
pass
departure = browser_control.find_element_by_xpath('//input[#placeholder="FROM"]')
browser_control.execute_script('arguments[0].setAttribute("class","glyph-input glyph-left-input form-control ng-pristine ng-valid ng-touched");', departure)
departure.send_keys("Berlin")
wait(browser_control, 5).until(EC.visibility_of_element_located(("xpath", "(//div[#class='location-primary']/span)[1]")))
departure.send_keys(Keys.RETURN)
destination = browser_control.find_element_by_xpath('//input[#placeholder="TO"]')
browser_control.execute_script('arguments[0].setAttribute("class","glyph-input glyph-left-input form-control ng-pristine ng-valid ng-touched");', destination)
destination.send_keys("Oslo")
wait(browser_control, 5).until(EC.visibility_of_element_located(("xpath", "(//div[#class='location-primary']/span)[4]")))
destination.send_keys(Keys.RETURN)
I'm using Selenium on http://seattle.bestparking.com/ to click through the parking garage markers (red, grey, blue), with the intention of opening the pop-up info window, so I can then scrap the info (on the "rate" page in the pop-up window). See my code at the end.
However, it appears that each of the garage marker's inner HTML changes (!!), after you click any other garage marker of the same color, then closing it (due to content reloading).
E.g.: when running my code, "Motif Seattle" garage shows up as div id = daily_colored_marker_577. But after any other marker of the same color is clicked on, "Motif Seattle" shows up as div id = daily_colored_marker_1042 ... and keeps on changing.
This makes it seemingly impossible to iterate through all the markers that I've selected (result of find_elements_by_class), since it will throw the following type or error when reaching the 2nd element in the selected list:
WebDriverException: unknown error: Element <div
class="daily_colored_marker_n_a" id="daily_colored_marker_344" onmouseover="show_hide_balloonWindowMonthly('', 'IMPARK', 'IMPARK M Street
Garage', '344', 400, 'n_a', offsetPosition('daily_colored_marker_344')...
</div> is not clickable at point (708, 543). Other element would receive the
click: <div class="daily_colored_marker_grey"...
My code:
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import time
driver = webdriver.Chrome()
driver.get('http://seattle.bestparking.com/')
driver.maximize_window()
'''Tells driver to wait until the "I understand" button to be clickable'''
wait = WebDriverWait(driver, 30)
element = wait.until(EC.element_to_be_clickable((By.XPATH, "//*
[#id='calendar_navigation_hint']/button")))
'''makes the disclaimer pop-up and the left menu go away, to reveal more of
the map'''
driver.find_element_by_xpath("//*#id='calendar_navigation_hint']
/button").click()
time.sleep(2)
driver.find_element_by_xpath("//*
[#id='map_left_panel_min_max_btn_div_oa']").click()
time.sleep(2)
'''zooms out one level'''
driver.find_element_by_xpath("//*
[#id='google_maps_zoom_control_minus_id']").click()
time.sleep(5)
'''find all the red markers and click on them'''
all_red = driver.find_elements_by_css_selector("div.daily_colored_marker_n_a")
time.sleep(3)
for x in range(0,len(all_red)):
all_red[x].click()
time.sleep(2)
driver.find_element_by_xpath("//*[#id='marker_window_close_text']").click()
time.sleep(3)
I don't think that error means what you think it means. If you look at it, it's stating that another element would receive the click. Selenium clicks on the center of an element. If you look at the map, there are some pins that cover each other. It's possible that it's trying to click the next element and it's partially covered by a different element so it throws the error.
Since I'm assuming you aren't trying to perform some user scenario, you can use JavascriptExecutor to execute the click and click the precise element.
You can see an example of how to do this in this question.