Selenium Explicit Waits for invisibility_of_element() not waiting at all - python

I am trying to make Selenium wait until a loader div is invisible.
These are my imports:
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.ui import WebDriverWait, Select
from selenium.webdriver.support.ui import expected_condition as EC
I first click on a button to open a pop up window with table data in it.
action.click()
action.perform()
After clicking I have to wait until I can press a button to export this data in a file. However, the time I have to wait varies wildly. Sometimes 10 seconds sometimes a few minutes. While this section is loading a loader shows up which prevents me from clicking anywhere on the screen.
I am trying to make Selenium wait until this loader is gone. However, for some reason, the script does not wait at all. Not even the maximum time, which is passed into the explicit wait function.
time.sleep(10)
print("Waiting for button")
wait = WebDriverWait(driver, 30) # I am just testing with 30, it will be a larger value
wait.until(EC.invisibility_of_element((By.XPATH, "//div[#class='loader']")))
print("Finished Waiting for button")
driver.find_element_by_xpath("//button[#class='export']").click()
First I am making Selenium wait 10 seconds so that the loader element can actually show up, which already shows up in 1-2 seconds.
After that I use print statement to check how long the script actually wait.
The script does not wait at all. It immediately continues which then causes an error because the button is not clickable yet.

You are passing a By.locator so instead of invisibility_of_element() you must be using invisibility_of_element_located().
First to wait for the visibility and then for the invisibility of the element you need to:
First induce WebDriverWait for the visibility_of_element_located()
Then induce WebDriverWait for the invisibility_of_element as follows:
WebDriverWait(driver, 30).until(EC.visibility_of_element_located((By.XPATH, "//div[#class='loader']")))
WebDriverWait(driver, 30).until(EC.invisibility_of_element_located((By.XPATH, "//div[#class='loader']")))
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

How to close browser(ChromeDriver) on time using Python

I made a Python program that opens my Youtube playlist using Selenium and I want to close that browser when all video is watched.
(I tried using time.sleep() but the problem is Youtube ads).
So, is there any way I can close my browser automatically when all video is watched?
When the video is finished //div[#class='ytp-autonav-endscreen-button-container'] element appears so you can wait until this element appearing and then close the driver.
You can also simply locate it by the class name 'ytp-autonav-endscreen-button-container' or other buttons / elements inside it.
So after staring the video use
WebDriverWait(driver, delay).until(EC.visibility_of_element_located((By.ID, 'ytp-autonav-endscreen-button-container')))
where delay is time that will be enough to the video to finish.
Lear more about webdriver explicit wait conditions here
Don't forget to add the essential imports
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
I suggest to make in in steps.
First step:
Wait for the last video in playlist:
By text:
last_video = driver.find_element_by_css_selector("#secondary .index-message.style-scope.ytd-playlist-panel-renderer:nth-child(1)").text == "10 /10"
Or by waiting for the last element in the playlist directly:
last_video = driver.find_element_by_css_selector("#secondary #items>.style-scope.ytd-playlist-panel-renderer:last-of-type").get_attribute("selected")
Second step:
After the first condition is true, wait for this video to finish, with this locator (Replay button)
video_ends = driver.find_element_by_css_selector(".ytp-chrome-controls button[title=Replay]")
For this you'll need to import:
from selenium.webdriver.common.by import By
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
And use it like this:
wait = WebDriverWait(driver, timeout_in_seconds)
wait.until(EC.visibility_of_element_located((By.CSS_SELECTOR, "#secondary .index-message.style-scope.ytd-playlist-panel-renderer:nth-child(1)").text == "10 /10")))
Timeout will depend of the length of playlist.
It is not a quick task, nobody will agree to finish it for you here.

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

Selenium Python | Wait for Entire Page to Load, Not Dependant on a Dynamic Element

I've seen similar questions to this but no one has given me a clear answer on whether or not it is possible for Selenium to know whether the entire page has loaded or not.
I know about expected_conditions.visibility_of_element_located((By.TAG_NAME, "div")) but I do not want a dynamic element to look for. I also don't want to wait a set number of seconds, I need the program to continue as soon as the entire page is loaded.
Is this possible?
You can use selenium webdriverWait:
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
driver = webdriver.Firefox()
driver.get("http://somedomain/url_that_delays_loading")
element = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.ID, "myDynamicElement"))
)
In the code above, Selenium will wait for a maximum of 10 seconds for an element matching the given criteria to be found. If no element is found in that time, a TimeoutException is thrown.
Or you can use the time module:
import time
time.sleep(10)
In the code above the program will wait for 10 seconds before executing the next line.

Wait time between each action

Hello I am new to python and I am trying to create an automation bot (I am very new to python) that logs into instagram and likes a certain number of posts but I am trying to figure out how to add a delay from when it enters the username information and password but I am not sure how to go about that, Also I would appreciate any feedback/recommendations thank you. Here is the code I have so far
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
browser = webdriver.Chrome()
def site_login():
browser.get('https://www.instagram.com/')
browser.find_element_by_name("username").send_keys(‘username’)
browser.find_element_by_name("password").send_keys(“password”)
browser.find_element_by_name("Log In").click() #not sure if this works
The time module should help you
import time
time.sleep(seconds) #Enter the time in seconds here
If you want to wait for a specified period then you can use time.sleep(timeInSeconds) which need import time.
import time
time.sleep(number_of_seconds)
But, however I would like to use the explicit wait. Unlike hard timeout, this will wait until the condition is met and continue the script.
# needed the imports
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait
# wait for the element and click (using xpath locator)
WebDriverWait(browser, 10).until(EC.presence_of_element_located((By.XPATH, "xpath_goes_here"))).click()
# wait for the element and enter value (using css locator)
WebDriverWait(browser, 10).until(EC.presence_of_element_located((By.CSS_SELECTOR, "css_locator_goes_here")))).send_keys("enter input")
# store the element and then perform action
loginButton = WebDriverWait(browser, 10).until(EC.presence_of_element_located((By.CSS_SELECTOR, "css_locator_goes_here"))))
loginButton.click()
you can use either CSS or xpath location strategy.
You can also use implicit wait at the driver level by adding below line of code.
browser.implicitly_wait(10)
Instead of using time.sleep(seconds) , I would recommend to use Explicit wait as the previous comment. Since due to environment changes time can be vary. So its better to use Explicit wait. Using time.sleep(seconds) will sleeps the current thread. It's a bad practice.
Thanks

Is there a way for selenium to click the like button (without using class)? (refer to picture)

tried a couple of methods with selenium, didn't work for me.
bot.find_element_by_css_selector('[data-testid="like"]').click()
bot.find_element_by_xpath("//a[#aria-label = 'Like']/*[name()='svg']").click()
bot.find_element_by_xpath("//a[#role = 'button']").click()
ss of the inspect segment
//edit//
my attempt to click the like button in this tweet!
https://twitter.com/RichardEudes/status/1196798030529335296
my code is as follows
# link is the url above
for link in stored_links:
bot.get(link)
bot.find_element_by_xpath("//div[#aria-label='Like']/div/div").click()
time.sleep(10)
I would add a WebDriverWait to your code sample as well:
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
# link is the url above
for link in stored_links:
bot.get(link)
like_button = WebDriverWait(bot, 10).until(
EC.presence_of_element_located((By.XPATH, "//div[#aria-label='Like']/div/div")))
like_button.click()
time.sleep(10)
I used the above code to successfully click the Like button on the tweet provided.
Breaking down this code sample:
from statements at the top -- these are used to include all of the Selenium libraries we need. By is used for locators, specifically By.XPATH here. WebDriverWait and expected_conditions are both used for the explicit wait, where we wait for the like button to be visible before clicking it.
WebDriverWait(bot, 10) declares a new instance of an explicit wait, specifically with a timeout of 10 seconds -- meaning, this method fails if the condition is not met within 10 seconds.
EC.presence_of_element_located is the condition we are waiting on -- in this case, we are waiting on the presence of a certain element. By.XPATH, "//div...div" specifies which element we are waiting on.
The line like_button = WebDriverWait(bot, 10).until(EC.presence_of_element_located((By.XPATH, "//div[#aria-label='Like']/div/div"))) is waiting on the presence of the element located through //div[#aria-label='Like']/div/div. If the element is not found within 10 seconds, a TimeoutException will be thrown.
Lastly, WebDriverWait returns the WebElement which is found after waiting -- so, like_button is the WebElement object we were waiting to exist. That is how we are able to click the button through like_button.click(), because we are using the reference to the WebElement we stored in the previous WebDriverWait step.

Categories