Cannot use WebDriverWait library properly in Python Selenium - python

Hello everyone I'm learning selenium recently and as I bet is a classic newbie mistake I filled my code with time.sleep which made everything really slow. So I started to learn about webdriverWait. I took some sample code and I have tried multiple things but I still get the error of "what you clicked is blocked by this other thing" meaning that the library did not crash but it also did not do anything. Which must mean I am doing something wrong. This is an error I can avoid if use the time.sleep function.
I'm using expected conditions, BY and action chains alongside WebDriverWait, though in my last test I tried to not use Acton chains to lower the possibilities of why its failing.
I'm using a company site that is probably under NDA so I don't have a public example to show this on, I tried searching for "pages with cover openings" but I couldn't find any, so if you guys know of any that I can use to illustrate this I would also find that really helpful. What is happening is that the site loads with a "cover" animation and after a few seconds the animation goes away to reveal the Button I'm looking for.
Environment info:
Using Pycharm community latest version
Using Selenium 4.0.0b2.post1 (I also tried in 3.9 to no results)
Using ChromeDriver 89 as my google chrome version is 89 as well [Version 89.0.4389.114 for Chrome]
Here are my code snippets:
Attempt #1:
from selenium import webdriver
from selenium.webdriver.support.wait import WebDriverWait
import selenium.webdriver.support.expected_conditions as EC
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.common.by import By
import selenium.webdriver.support.ui as ui
def test(driver, actions, delay):
cart = "//header/div[1]/div[1]/a[2]/*[1]"
cartxp = WebDriverWait(driver, delay).until(EC.visibility_of_element_located((By.XPATH, cart)))
actions.move_to_element(cartxp).perform()
cartclk = driver.find_element_by_xpath(cart).click()
Attempt #2: Using UI library
from selenium import webdriver
from selenium.webdriver.support.wait import WebDriverWait
import selenium.webdriver.support.expected_conditions as EC
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.common.by import By
import selenium.webdriver.support.ui as ui
def test2(driver, delay, actions):
cart = "//header/div[1]/div[1]/a[2]/*[1]"
cartxp = ui.WebDriverWait(driver, delay).until(EC.visibility_of_element_located((By.XPATH, cart)))
actions.move_to_element(cartxp).perform()
cartclk = driver.find_element_by_xpath(cart).click()
Attempt #3: Not using Action chains
from selenium import webdriver
from selenium.webdriver.support.wait import WebDriverWait
import selenium.webdriver.support.expected_conditions as EC
from selenium.webdriver.common.by import By
def test3(driver, delay):
wait = WebDriverWait(driver, delay)
cart = "//header/div[1]/div[1]/a[2]/*[1]"
button = wait.until(EC.element_to_be_clickable((By.XPATH, cart)))
cartclk = driver.find_element_by_xpath(cart).click()
All of these have a main method that just has:
driver = webdriver.Chrome()
test3(driver, 30)
driver.get('Site that I cant reveal cuz of NDA')
action = ActionChains(driver)
The error I get is:
Message: element click intercepted: Element ... is not clickable at point (1183, 27). Other element would receive the click
Thanks in advance for any help!
Edit: After some comments changed my xpath to //a[#class='header__cart'] both the previous and this one leads to a single result If I use it on chrome inspect to look for the button, additionally it works as intended if I use it to actually click the button after using time.sleep() to wait out the animation
Additionally just in case tried using the try catch as they did on the suggested question. It also failed
Attempt 4: surrounding in a try-catch
def test4(driver, delay):
cart = "//a[#class='header__cart']"
try:
my_elem = WebDriverWait(driver, delay).until(EC.visibility_of_element_located((By.XPATH, cart)))
print
"Page is ready!"
except TimeoutException:
print
"Loading took too much time!"
cart_btn = driver.find_element_by_xpath(cart)
cart_btn.click()
Error: selenium.common.exceptions.ElementClickInterceptedException: Message: element click intercepted: Element <a href="/cart" class="header__cart" data-items-in-cart="0" )="">... is not clickable at point (1200, 27). Other element would receive the click
To clarify what I meant earlier this works:
cart = "//a[#class='header__cart']"
time.sleep(20)
cartclk = driver.find_element_by_xpath(cart).click()

Related

Selenium script to detect presence of button and to click on it when it appears not working

Python/coding newb, beware!
Im writing a script to download from youtube from " https://ytmp3.cc/en13/ ". I had written a click script using pyautogui but the problem being that the download button appears anywhere betweeen 1 and 15 seconds of entering the link. So i wanted to re-code it in a Selenium window to dynamically wait until the button is visible and then continue with the click script. I have tried about 15 ways but cant get it to work
library blah :
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.webdriver.support.expected_conditions import presence_of_element_located
from selenium.common.exceptions import NoSuchElementException
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import TimeoutException
ways i tried to get it to work:
without waits, results in NosuchElement Exception
def check_exists():
try:
while True:
a=driver.find_element(By.LINK_TEXT, "Download")
a.click()
except NoSuchElementException:
time.sleep(10)
the syntax of this is most probably wrong
i tried a couple different variations of implicit and explicit waits but couldnt get it to work. Is there some javascript on the site linked above thats messing with my code?
in a separate .py, running
#driver.find_element(By.LINK_TEXT, "Download").click()
#either the line above or below works at finding the element, and clicking it
driver.find_element_by_link_text("Download").click()
I just need help getting the line above ^ into an explicit wait, but i dont have the language knowledge of how to do it yet. i would appreciate some help, thanks in advance!
You can use webdriver wait to wait until button is displayed. Tried the below code which works for me
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
video_path = "your_video_path"
waitTime=10
driver = webdriver.Chrome("./chromedriver.exe")
driver.get("https://ytmp3.cc/")
element = driver.find_element_by_id("input")
element.send_keys(video_path)
driver.find_element_by_id("submit").click()
try:
# wait 10 seconds before looking for element
element = WebDriverWait(driver, waitTime).until(
EC.presence_of_element_located((By.LINK_TEXT,"Download"))
)
driver.find_element_by_link_text("Download").click()
finally:
print(driver.title)
You can update your required wait time in waitTime variable in seconds so if the value is 10 selenium will wait and check for elements upto 10 seconds

Python Selenium - send_keys not sending any information to element

I am trying out Selenium for the first time so I apologize if there is an obvious mistake or problem with my code.
from selenium import webdriver
driver = webdriver.Chrome()
driver.get('https://youtube.com')
searchBox = driver.find_element_by_id('search')
searchBox.send_keys('Programming')
searchButton = driver.find_element_by_id('search-icon-legacy')
searchButton.click()
So I tried this and it loads the page fine but, it does not input any characters into the searchBox (I quadruple checked that the id was correct - copied it directly from the inspector).
NOTE:
My internet is really REALLY slow and it takes YouTube approx. 20 seconds to fully load, so I thought that was an issue so I tried;
...
driver.get('https://youtube.com')
driver.implicitly_wait(30)
searchBox = driver.find_element_by_id('search')
...
But this did not work either.
I did use XPATH instead of finding it by element ID at the start and that did not work.
I checked and copied the XPATHs and IDs directly from the inspector and nothing so far has inputted anything into the textbox.
What could be the problem? (1)
and does the webdriver wait for the page to load/find the element before doing anything after it being initialized with the driver.get('websiteAddress')? (2)
NOTE: I double checked that I was selecting the right element as well.
To send keys to the input tag with id = search. We use webdriver waits to allow the element to be usable after driver.get so the page loads correctly.
driver.get('https://youtube.com')
WebDriverWait(driver, 30).until(EC.element_to_be_clickable((By.XPATH, "//input[#id='search']"))).send_keys("Programming")
Import
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
If you don't know the waiting time:
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
delay = 40
WebDriverWait(driver, delay).until(EC.presence_of_element_located((By.XPATH, "//form[#role='form']//input[#id='username']")))
Then it just waits on the element, for as log as delay is, but will continue as soon as the element is found, that the best way to wait on slow connections.
To relate elements more easily you can use ChroPath, it is an extension for google chrome / edge that allows you to see the path of an element, through cssSelector, Abs XPath, Rel XPath and the tag name, so when your code is not working you can try these other ways. Particularly this extension helps me a lot.

Unable to input values fully in a text field using send keys. Only partial values entered and no error shown

Unable to input values fully in a textbox field using send keys. Only partial values entered and no error shown.
Attempted sending keys with a wait.
Attempted sending keys slowly.
[Edit] - This is the entire script as requested in the comments below
from selenium.webdriver.support.ui import Select
from selenium.webdriver.support.wait import WebDriverWait
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as ec
import time
from time import sleep
from selenium.webdriver.common.keys import
Keysdriver=webdriver.Chrome(executable_path="C:\Program Files (x86)\Drivers\chromedriver.exe")
driver.get("https://www.volunteers.ae/register.aspx")
driver.find_element_by_xpath("//*[#id='topnav_btnLangShift']").click()
driver.find_element(By.ID,'body_txtFName').send_keys("RADHIKA")
driver.find_element(By.ID,'body_txtLName').send_keys("PORANKI")
driver.find_element_by_id("body_txtEmail").send_keys("radhika.po#gmail.com")
element=driver.find_element_by_id("body_ddGender")
dropdown=Select(element)dropdown.select_by_value("Female")
driver.find_element_by_id("ctl00_body_txtDOB_dateInput").send_keys("08/04/1986")
element=driver.find_element_by_id("body_ddNationality")
dropdown=Select(element)
dropdown.select_by_value("India")
element=driver.find_element_by_id("body_ddCountryOfResidence")
dropdown=Select(element)
dropdown.select_by_value("+971")
element=driver.find_element_by_id("body_ddEmirate")
dropdown=Select(element)
dropdown.select_by_value("DUBAI")
time.sleep(10)
element=driver.find_element_by_id("body_ddCity")
dropdown=Select(element)
dropdown.select_by_value("DUBAI CITY")
def ClickAndSlowType(element, text):
element.click()
sleep(1) # let scripts run
for t in list(text):
print(t)
element.send_keys(t)
sleep (0.1)
mobile = WebDriverWait(driver, 8).until(ec.element_to_be_clickable((By.XPATH, "//*[#id='ctl00_body_txtEtisalat']")))
mobile.click()
mobile.send_keys("68862632")
What's the problem when you run your script?
I enhanced your script with a wait action and it works great:
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.Chrome()
driver.get('https://www.volunteers.ae/register.aspx')
mobile = WebDriverWait(driver, 8).until(EC.element_to_be_clickable((By.XPATH, "//*[#id='ctl00_body_txtEtisalat']")))
mobile.click()
mobile.send_keys("68862632")
Output looks like this:
There does seem to be some scripting at work in the page. Evertyime you click and type it resents the field. However, the above code still seems to work.
If there's a problem, let me know what's happening (with any relevant errors that occur) and i'll look again.
[Update!]
Based on the comments below, try typing with a delay.
Add this import:
from time import sleep
Add this function:
def ClickAndSlowType(element, text):
element.click()
sleep(1) # let scripts run
for t in list(text):
print(t)
element.send_keys(t)
sleep (0.1)
Run this:
mobile = WebDriverWait(driver, 8).until(EC.element_to_be_clickable((By.XPATH, "//*[#id='ctl00_body_txtEtisalat']")))
ClickAndSlowType(mobile, "68862632")
I can't recreate your issue but this also works for me so worth a try. It just types a bit slower in case of the funky in-page script issues.
Let me know how it goes.
If you can update your question with your entire i code i might be able to recreate and provide a tried and tested answer. (no one likes "it worked for me")
As it works locally but not on #Paul 's machine : we need to debug it . Try this at the end of the script and please tell exactly what you see happen to the field and what the output from the prints on the console:
def WaitForDocumentReadyState():
print("Ready State Before: " + driver.execute_script('return document.readyState'))
WebDriverWait(driver, 10).until(lambda driver: driver.execute_script('return document.readyState') == 'complete')
def ClickAndSlowType(element, text):
element.click()
WaitForDocumentReadyState()
sleep(1) # let scripts run
for t in list(text):
element.send_keys(t)
WaitForDocumentReadyState()
sleep (0.5)
sleep(1) # let scripts run
WaitForDocumentReadyState()
mobile = WebDriverWait(driver, 8).until(ec.element_to_be_clickable((By.XPATH, "//*[#id='ctl00_body_txtEtisalat']")))
#mobile.click()## REMOVED
#mobile.send_keys("68862632") ## REMOVED
ClickAndSlowType(mobile, "68862632") ## using the function

Selenium not able to locate element that actually exists

I am automating a boring data entry task, so I created a program that basically clicks and types for me using selenium. It runs great! except for when it reaches this specific "Edit Details..." element that I need clicked, however, selenium is unable to locate the element regardless of whatever method I try.
I've tried using a CSS selector that tried to access the ID to no avail. I also tried using XPATH, as well as trying to be more specific by giving it a 'contains' statement with the button text. As last resort, I used the selenium IDE to see what locator it registers when I physically click the button and it used the exact same ID that I state in my code. I am completely lost on how to go about fixing this.
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.common.exceptions import *
import pyautogui as py
import time, sys, os, traceback
#Launching Browser
browser = webdriver.Ie()
wait = WebDriverWait(browser, 15) #Waiting
#Laziness Functions
def clickCheck(Method, Locator, elemName):
wait.until(EC.element_to_be_clickable((Method, Locator)))
print(elemName + ' Clickable')
#Commence main function
try:
#Do alot of Clicks and Stuff until it reaches "Edit Details..." element
"""THIS IS WHERE THE PROBLEM LIES"""
time.sleep(3)
clickCheck(By.CSS_SELECTOR, 'td[id="DSCEditObjectSummary"]', "Edit Details")
elemEdit = browser.find_element_by_css_selector('td[id="DSCEditObjectSummary"]')
elemEdit.click()
#FAILSAFES
except:
print('Unknown error has Occured')
exc_info = sys.exc_info()
traceback.print_exception(*exc_info)
del exc_info
finally: #Executes at the end and closes all processes
print('Ending Program')
browser.quit()
os.system("taskkill /f /im IEDriverServer.exe")
sys.exit()
raise exception_class(message, screen, stacktrace)
selenium.common.exceptions.NoSuchElementException: Message: Unable to find element with css selector == [id="DSCEditObjectSummary"]
This is what I get as an error, all I want is for the element to be clicked just like all other elements are being located by CSS_Selectors. The image below indicates in blue the exact line for the "Edit Details..." button.
Edit Details Button
It looks like the issue may be with the page loading slowly, or as another commenter mentioned it's in an iFrame, etc. I typically try clicking by using X/Y coordinates with a macro tool like AppRobotic if you're running this on Windows. If it's an issue with the page loading slowly, I usually try stopping the page load, and interacting with the page a bit, something like this should work for you:
import win32com.client
from win32com.client import Dispatch
x = win32com.client.Dispatch("AppRobotic.API")
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.common.exceptions import *
import pyautogui as py
import time, sys, os, traceback
#Launching Browser
browser = webdriver.Ie()
wait = WebDriverWait(browser, 15) #Waiting
#Laziness Functions
def clickCheck(Method, Locator, elemName):
wait.until(EC.element_to_be_clickable((Method, Locator)))
print(elemName + ' Clickable')
driver.get('https://www.google.com')
# wait 20 seconds
x.Wait(20000)
# scroll down a couple of times in case page javascript is waiting for user interaction
x.Type("{DOWN}")
x.Wait(2000)
x.Type("{DOWN}")
x.Wait(2000)
# forcefully stop pageload at this point
driver.execute_script("window.stop();")
# if clicking with Selenium still does not work here, use screen coordinates
x.MoveCursor(xCoord, yCoord)
x.MouseLeftClick
x.Wait(2000)
I am posting this answer more so for other folks who might be running into the same problem and stumble upon this post. As #PeterBejan mentioned, the element I was trying to click was nested in an iframe. I tried accessing the iframe except I was thrown a NoSuchFrameException. Further digging revealed that this frame was nested inside 3 other frames and I had to switch to each frame from top level down, to access the element. This was the code I used
wait.until(EC.frame_to_be_available_and_switch_to_it("TopLevelFrameName"))
wait.until(EC.frame_to_be_available_and_switch_to_it("SecondaryFrameName"))
wait.until(EC.frame_to_be_available_and_switch_to_it("TertiaryFrameName"))
wait.until(EC.frame_to_be_available_and_switch_to_it("FinalFrameName"))
clickCheck(By.ID, 'ElementID', "Edit Details")
elemEdit = browser.find_element_by_id("ElementID")
elemEdit.click()

After submitting form, how to wait for element to load before clicking on said element? (Selenium / Python)

I'm using Selenium and coding in Python.
After I submit a Javascript form, the page proceeds to load dynamically for results. I am essentially waiting for an element (a specific button link) to appear / finish loading so I can click on it. How do I go about doing this?
You can use WebDriverWait, Documentation here,
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait # available since 2.4.0
from selenium.webdriver.support import expected_conditions as EC # available since 2.26.0
ff = webdriver.Firefox()
ff.get("http://somedomain/url_that_delays_loading")
try:
element = WebDriverWait(ff, 10).until(EC.presence_of_element_located((By.ID, "myDynamicElement")))
finally:
ff.quit()
Also, take a look at a similiar question, How can I make Selenium/Python wait for the user to login before continuing to run?

Categories