Page keep loading infinitly in try except statement of function - python-3.x

During automating of review posting, I am stuck in a situation where a function having try-except statement. You may get my point clearly by reading below code.
This method writes reviews and return True or False
def write_review(browser,row):
try:
WebDriverWait(browser, 20).until(EC.presence_of_element_located((By.CSS_SELECTOR, 'label[for="rating-5"]'))).click()
sleep(1)
browser.find_element_by_id("review.userNickname").clear()
browser.find_element_by_id("review.userNickname").send_keys(row['nickname'].replace(' ',''))
sleep(1)
browser.find_element_by_id("review.title").clear()
browser.find_element_by_id("review.title").send_keys(row['headline'])
sleep(1)
browser.find_element_by_id("review.reviewText").clear()
browser.find_element_by_id("review.reviewText").send_keys(row['review'])
sleep(1)
browser.find_element_by_css_selector('label[for="review.netPromoterScore.10"]').click()
sleep(1)
browser.find_element_by_css_selector('button[class*="js-preview"]').click()
sleep(3)
print('Submitting a review....')
WebDriverWait(browser, 20).until(EC.presence_of_element_located((By.CSS_SELECTOR, 'a[class*="js-submit"]'))).click()
sleep(5)
return True
except Exception as ex::
print(str(ex))
return False
In case if any review is not posted successfully, I have implemented function call like this
browser.get(url)
success = write_review(browser,row)
if success==False:
while success!=True:
browser.get(url)
print('Again submitting...')
success = write_review(browser,row)
But the problem with above code is that in case of unsuccessful review posting, the page keep loading again and again without having entered any data in review body. Actually the error occurs at the line after print('Submitting a review....') statement which means click action before this line sometimes doesn't load javascript correctly. That's why I loaded that page again with the same statement of function call after while loop. Here are some error messages
Continue to review posting....
Submitting a review....
Submitting a review....
Submitting a review....
Submitting a review....
Message: element not visible
(Session info: chrome=89.0.4389.114)
(Driver info: chromedriver=2.41.578700 (2f1ed5f9343c13f73144538f15c00b370eda6706),platform=Linux 5.8.0-49-generic x86_64)
Again submitting...
Message: unknown error: Element <label for="rating-5" class="">...</label> is not clickable at point (468, 17). Other element would receive the click: <input id="search-autocomplete" type="text" name="query" autocomplete="off" autocorrect="off" placeholder="Search food, toys, prescriptions and more" role="combobox" aria-controls="search__suggestions" aria-haspopup="listbox" aria-label="Search food, toys, prescriptions and more" class="sfw-search__input">
(Session info: chrome=89.0.4389.114)
(Driver info: chromedriver=2.41.578700 (2f1ed5f9343c13f73144538f15c00b370eda6706),platform=Linux 5.8.0-49-generic x86_64)
Again submitting...
Message: unknown error: Element <label for="rating-5" class="">...</label> is not clickable at point (468, 18). Other element would receive the click: <input id="search-autocomplete" type="text" name="query" autocomplete="off" autocorrect="off" placeholder="Search food, toys, prescriptions and more" role="combobox" aria-controls="search__suggestions" aria-haspopup="listbox" aria-label="Search food, toys, prescriptions and more" class="sfw-search__input">
(Session info: chrome=89.0.4389.114)
(Driver info: chromedriver=2.41.578700 (2f1ed5f9343c13f73144538f15c00b370eda6706),platform=Linux 5.8.0-49-generic x86_64)

Place print/log inside 'except' block with exception info message and check why exceptions keep rising. Muting any exception especially global without logging error message is really bad idea.
Example:
try:
# Your code
except Exception as ex:
print(str(ex))
return False

If you want to prevent a infinite loop,you can try this
browser.get(url)
success = write_review(browser,row)
if success==False:
trytimes = 0
maxtrytimes = 10
while success!=True:
browser.get(url)
print('Again submitting...')
success = write_review(browser,row)
trytimes+=1
if trytimes>maxtrytimes:
print("write_review failed too many times")
break

If you want to click the button:
Import:
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
Add wait:
wait = WebDriverWait(driver, timeout=30)
wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, ".a[class="js-submit"]")))
list_view = driver.find_element_by_css_selector('a[class="js-submit"]')
list_view.click()
You are using presence_of_element_located but it will not wait for the button completely.
Next, remove loop and remove sleeps.
Replace all sleeps with explicit wait like mentioned above, that will wait for the element that takes most time to load. Use EC.visibility_of_element_located to wait for an element to become visible.
You are ddosing the form because some locators are not completely loaded or some locators are incorrect. time.sleep(1) before each input is a very bad solution.
And finally, check if a[class="js-submit"] is unique.

Related

Stale Element Reference Exception occurred even though I explicitly ignored the exception using ignored_exceptions

Why is the StaleElementReferenceException still raised even though I ignored the exception? The code will eventually run successfully after a few tries but how can I make it wait until the element is clickable to avoid any exception?
import sys
from selenium.common.exceptions import StaleElementReferenceException
while True:
try:
WebDriverWait(driver, 10, ignored_exceptions=[StaleElementReferenceException]).until(ec.element_to_be_clickable((By.XPATH,"//button[contains(text(), 'Performance Summary')]"))).click()
break
except Exception as e:
exc_type, exc_obj, exc_tb = sys.exc_info()
print(e, exc_type, exc_tb.tb_lineno)
print('Retrying...')
From the source code of WebDriverWait:
class WebDriverWait:
def __init__(
self,
driver,
timeout: float,
poll_frequency: float = POLL_FREQUENCY,
ignored_exceptions: typing.Optional[WaitExcTypes] = None,
):
"""Constructor, takes a WebDriver instance and timeout in seconds.
:Args:
- driver - Instance of WebDriver (Ie, Firefox, Chrome or Remote)
- timeout - Number of seconds before timing out
- poll_frequency - sleep interval between calls
By default, it is 0.5 second.
- ignored_exceptions - iterable structure of exception classes ignored during calls.
By default, it contains NoSuchElementException only.
Example::
from selenium.webdriver.support.wait import WebDriverWait \n
element = WebDriverWait(driver, 10).until(lambda x: x.find_element(By.ID, "someId")) \n
is_disappeared = WebDriverWait(driver, 30, 1, (ElementNotVisibleException)).\\ \n
until_not(lambda x: x.find_element(By.ID, "someId").is_displayed())
"""
self._driver = driver
self._timeout = float(timeout)
self._poll = poll_frequency
# avoid the divide by zero
if self._poll == 0:
self._poll = POLL_FREQUENCY
exceptions = list(IGNORED_EXCEPTIONS)
if ignored_exceptions:
try:
exceptions.extend(iter(ignored_exceptions))
except TypeError: # ignored_exceptions is not iterable
exceptions.append(ignored_exceptions)
self._ignored_exceptions = tuple(exceptions)
It is worth to notice that ignored_exceptions is not iterable.
So NoSuchElementException being the default exception and StaleElementReferenceException being purposely added, can be ignored only once. Hence the second time StaleElementReferenceException is no more handled.
The problem is that once you get a StaleElementReferenceException, you can't just wait it out. Here's how stale elements work.
element = driver.find_element(By.ID, "someId")
driver.refresh() # or anything that changes the portion of the page that 'element' is on
element.click() # throws StaleElementReferenceException
At this point a StaleElementReferenceException is thrown because you had a reference to the element and then lost it (the element reference pointer points to nothing). No amount of waiting is going to restore that reference.
The way to "fix" this is to grab the reference again after the page has changed,
element = driver.find_element(By.ID, "someId")
driver.refresh()
element = driver.find_element(By.ID, "someId") # refetch the reference after the page refreshes
element.click()
Now the .click() will work without error.
Most people that run into this issue are looping through a collection of elements and in the middle of the loop they click a link that navigates to a new page or something else that reloads or changes the page. They later return to the original page and click on the next link but they get a StaleElementReferenceException.
elements = driver.find_elements(locator)
for element in elements
element.click() # navigates to new page
# do other stuff and return to first page
The first loop works fine but in the second loop the element reference is dead because of the page change. You can change this loop to force the elements collection to be refetched at the start of each loop
for element in driver.find_elements(locator)
element.click() # navigates to new page
# do other stuff and return to first page
Now the loop will work. This is just an example but hopefully it will point you in the right direction to fix your code.

Website login loading endlessly when I use find_element()

I'm having a problem with Selenium, when fetching an input from a login from a page. For some reason, whenever I store the element in a variable, the site in question, when trying to log in, keeps loading infinitely. However, if I remove that part of the code, and enter the login credentials manually, the login is done normally. I will explain below:
This is how the page input I try to access looks like:
<input id="txtUsername" name="txtUsername" class="random-name" placeholder="User" type="text" required="required" aria-required="true" autocomplete="off" autocorrect="off" autocapitalize="off">
<input id="txtPassword" name="txtUsername" class="random-name" placeholder="User" type="text" required="required" aria-required="true" autocomplete="off" autocorrect="off" autocapitalize="off">
And this is my python code:
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver import chrome
from time import sleep
options = webdriver.ChromeOptions()
browser = webdriver.Chrome(options=options)
site = "www.google.com"
browser.get(site)
def make_login(browser):
sleep(1)
login = browser.find_element(By.ID, "txtUsername")
login.click()
login_text = "User"
for x in login_text:
sleep(0.15)
login.send_keys(x)
senha = navegador.find_element(By.ID, "txtPassword")
senha.click()
senha_text = "Password"
for x in senha_text:
sleep(0.15)
senha.send_keys(x)
if __name__ == "__main__":
make_login(browser)
When I run it, it clicks on each input, enters the password, as it should. However, when I click log in, the website keeps loading endlessly.
If i remove this part:
login = browser.find_element(By.ID, "txtUsername")
login.click()
senha = navegador.find_element(By.ID, "txtPassword")
senha.click()
And manually clicking on the inputs, he enters the site normally...
I appreciate anyone who can help me.
Have you tried to use only use send_keys()? So, your code will look like:
def make_login(browser):
sleep(1)
login = browser.find_element(By.ID, "txtUsername")
login_text = "User"
login.send_keys(login_text)
senha = navegador.find_element(By.ID, "txtPassword")
senha_text = "Password"
senha.send_keys(senha_text)
As shown in selenium documentation send_keys() method is enough to fill input fields.
But if you're trying to access sites like bet365 it's almost certainly the website prohibiting your code. Take a look at this post and its answers.

How to click on a hidden button with selenium through Python

I’m trying to click an Upload from my Computer button on a page that has the source below.
I’m using selenium and tried several different approaches. The past failed approaches are commented out below, along with the current failed approach. The error that’s returned with the current approach is below.
Can anyone see what the issue might be and suggest how to solve it? I’m new to selenium so if someone can provide some explanation of what the html is doing and how their code solves the issue as well it would be really helpful for my understanding.
HTML code of the button:
<div class="hidden-xs">
<label for="fuUploadFromMyComputer" class="hidden">
Upload from my Computer
</label>
<input id="fuUploadFromMyComputer" type="file" name="upload">
<button id="btnUploadFromMyComputer"
class="center-block btn btn-white-fill btn-block "
data-resume-type="COMPUTER" type="submit">
<i class="zmdi zmdi-desktop-mac"></i>
Upload from my Computer
</button>
</div>
attempts:
# clicking upload button
# upload_btn = driver.find_element_by_id("fuUploadFromMyComputer")
# upload_btn = driver.find_element_by_css_selector(
# '.center-block.btn.btn-white-fill.btn-block')
# upload_btn = driver.find_element_by_link_text('Upload from my Computer')
# upload_btn.click()
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
WebDriverWait(driver, 20).until(EC.element_to_be_clickable(
(By.CSS_SELECTOR, "div.center-block btn.btn-white-fill.btn-block"))).click()
error:
---------------------------------------------------------------------------
TimeoutException Traceback (most recent call last)
<ipython-input-43-8fd80ff3c690> in <module>()
14 from selenium.webdriver.support import expected_conditions as EC
15
---> 16 WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.CSS_SELECTOR, "div.center-block btn.btn-white-fill.btn-block"))).click()
17
18 time.sleep(3)
~/anaconda/envs/py36/lib/python3.6/site-packages/selenium/webdriver/support/wait.py in until(self, method, message)
78 if time.time() > end_time:
79 break
---> 80 raise TimeoutException(message, screen, stacktrace)
81
82 def until_not(self, method, message=''):
TimeoutException: Message:
To click on the element with text as Upload from my Computer you need to induce WebDriverwait for the element to be clickable and you can use either of the following solutions:
CSS_SELECTOR:
WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.CSS_SELECTOR, "button.center-block.btn.btn-white-fill.btn-block#btnUploadFromMyComputer"))).click()
XPATH:
WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, "//button[#class='center-block btn btn-white-fill btn-block ' and #id='btnUploadFromMyComputer']"))).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
Selenium's click() does not support to operate on invisible element. Thus please double confirm the button is visible or not when your code intend to click it.
If the button is not visible, how do you click it hands-on? Thus change your script to following the human steps to make the button visible before you can click it.
Back to your failure on below code
WebDriverWait(driver, 20).until(EC.element_to_be_clickable(
(By.CSS_SELECTOR, "div.center-block btn.btn-white-fill.btn-block"))).click()
The reason is you give a wrong css selector which can't find any element from the page util reach the waiting timeout.
The correct css selector of the button can be any one of following:
button.center-block.btn.btn-white-fill.btn-block
button#btnUploadFromMyComputer
For C#, I used IJavaScriptExecutor to click on element. You may search this solution for Python syntax
public static void scrollElementToClick(IWebDriver driver, IWebElement element)
{
IJavaScriptExecutor ex = (IJavaScriptExecutor)driver;
ex.ExecuteScript("arguments[0].click();", element);
}

Error "Other element would receive the click" in Python

I tried to click a link like this:
<div class="loading" style="display:none;">
<p class="btn blue"><span>さらに表示</span></p>
</div>
and I used this code:
element = WebDriverWait(driver, 30).until(lambda x: x.find_element_by_css_selector(".btn.blue")) # #UnusedVariable
element.click()
I got an error like this, what can I do to solve it?
selenium.common.exceptions.WebDriverException: Message: unknown error: Element <p class="btn blue">...</p> is not clickable at point (391, 577). Other element would receive the click:
(Session info: headless chrome=69.0.3497.100)
(Driver info: chromedriver=2.41.578737 (49da6702b16031c40d63e5618de03a32ff6c197e),platform=Windows NT 6.1.7601 SP1 x86_64)
Element on which you are trying to click has been covered by some other element so that other element getting the click instead of the actual element.
There may be following possibilities that actual element not getting clicked:
Case 1. lets say if its a loader which comes while your element getting load and get invisible after some time.
Solution: Here you have to wait until the loader get invisible and then have to perform click on actual element
from selenium.webdriver.support import expected_conditions as EC
wait = WebDriverWait(driver, 10)
element = wait.until(EC.invisibility_of_element_located((By.ID, 'loader_element_id')))
element_button = wait.until(EC.element_to_be_clickable((By.ID, 'your_button_id')))
element_button.click()
Case 2. actual element is not visible within browser dimension and covered by some overlay element.
Solution: Here you need to scroll to the required element and then have to perform the click
from selenium.webdriver.common.action_chains import ActionChains
element = driver.find_element_by_id("your_element_id")
actions = ActionChains(driver)
actions.move_to_element(element).perform()
OR use can use execute_script like :
driver.execute_script("arguments[0].scrollIntoView();", element)
OR perform the click using JavaScript.
driver.execute_script("arguments[0].click();", element)
Note: Please make necessary correction as per Python syntax if require.
You may use action class to click your element,
from selenium.webdriver import ActionChains
actions = ActionChains(driver)
actions.move_to_element(element).click().perform()
As per the HTML and your code trials you have attempted to click on the <span> tag in stead you should try to invoke click() on the <a> tag as follows:
Using css_selector:
element = WebDriverWait(driver, 30).until(lambda x: x.find_element_by_css_selector("div.loading a[onclick^='get_more']"))
element.click()
Using xpath:
element = WebDriverWait(driver, 30).until(lambda x: x.find_element_by_xpath("//p[#class='btn blue']/span[contains(.,'さらに表示')]//following::a[contains(#onclick,'get_more')]"))
element.click()
This is my function for click element on every condition:
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
def xpathElement(driver, xpath):
return WebDriverWait(driver, config['waitSeconds']).until(EC.presence_of_element_located((By.XPATH, xpath)))
def scroll2elementByXpath(driver, xpath):
element = xpathElement(driver, xpath)
element.location_once_scrolled_into_view
def clickObject(driver, xpath, firstTime=True, useJS=False):
try:
element = xpathElement(driver, xpath)
if useJS:
driver.execute_script("arguments[0].click();", element)
else:
element.click()
except Exception as exception:
if firstTime:
scroll2elementByXpath(driver, xpath)
clickObject(driver, xpath, desc, False)
elif not useJS:
clickObject(driver, xpath, desc, firstTime, True)
else:
assert False, exception

selenium python ElementNotInteractableException [duplicate]

Here I have the image of my code and the image of my error. Can anyone help me to resolve this issue?
ElementNotInteractableException
ElementNotInteractableException is the W3C exception which is thrown to indicate that although an element is present on the HTML DOM, it is not in a state that can be interacted with.
Reasons & Solutions :
The reason for ElementNotInteractableException to occur can be numerous.
Temporary Overlay of other WebElement over the WebElement of our interest :
In this case, the direct solution would have been to induce ExplicitWait i.e. WebDriverWait in combination with ExpectedCondition as invisibilityOfElementLocated as folllows:
WebDriverWait wait2 = new WebDriverWait(driver, 10);
wait2.until(ExpectedConditions.invisibilityOfElementLocated(By.xpath("xpath_of_element_to_be_invisible")));
driver.findElement(By.xpath("xpath_element_to_be_clicked")).click();
A better solution will be to get a bit more granular and instead of using ExpectedCondition as invisibilityOfElementLocated we can use ExpectedCondition as elementToBeClickable as follows:
WebDriverWait wait1 = new WebDriverWait(driver, 10);
WebElement element1 = wait1.until(ExpectedConditions.elementToBeClickable(By.xpath("xpath_of_element_to_be_clicked")));
element1.click();
Permanent Overlay of other WebElement over the WebElement of our interest :
If the overlay is a permanent one in this case we have to cast the WebDriver instance as JavascriptExecutor and perform the click operation as follows:
WebElement ele = driver.findElement(By.xpath("element_xpath"));
JavascriptExecutor executor = (JavascriptExecutor)driver;
executor.executeScript("arguments[0].click();", ele);
I got this because the element I wanted to interact with was covered by another element. In my case it was an opaque overlay to make everything r/o.
When trying to click an element UNDER another element we usualy get "... other Element would receive the click " but not always :.(
This Exception we get when the element is not in an interactable state. So we can use wait till the element is Located or become clickable.
Try using the Implicit wait:
driver.manage().timeouts().implicitlyWait(Time, TimeUnit.SECONDS);
If this is not working use Explicit wait:
WebDriverWait wait=new WebDriverWait(driver, 20);
WebElement input_userName;
input_userName = wait.until(ExpectedConditions.elementToBeClickable(By.tagName("input")));
input_userName.sendkeys("suryap");
You can use ExpectedCondition.visibilityOfElementLocated() as well.
You can increase the time, for example,
WebDriverWait wait=new WebDriverWait(driver, 90);
A solution to this for Javascript looks like this. You will have to modify the time to suit your need.
driver.manage().setTimeouts({ implicit: 30000 });
Hope this is helpful to someone.
see the docs for reference
Actually the Exception is Element Not Visible
The best practice is to use Implicit wait below driver Instantiation so it get sufficient time to find element throughout the exception
driver.get("http://www.testsite.com");
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
Still facing issue as some element require more time. Use ExplicitWait for individual element to satisfy certain condition
In your case you are facing element not visible exception then use wait condition in following way-
WebDriverWait wait = new WebDriverWait(driver, 120);
wait.until(ExpectedConditions.visibilityOfElementLocated(By.your_Elemetnt));
In my case issue was because there is some animation, and that element is not visible for some duration. And hence exception was occurring.
For some reason I couldn't make ExpectedConditions.visibilityOfElementLocated work, so I created a code to wait for some hardcoded seconds before proceeding.
from selenium.webdriver.support.ui import WebDriverWait
def explicit_wait_predicate(abc):
return False
def explicit_wait(browser, timeout):
try:
Error = WebDriverWait(browser, timeout).until(explicit_wait_predicate)
except Exception as e:
None
And now I am calling this explicit_wait function wherever I want to wait for sometime e.g.
from selenium import webdriver
from selenium.webdriver.common.by import By
browser = webdriver.Safari()
browser.get('http://localhost')
explicit_wait(browser,5) # This will wait for 5 secs
elem_un = browser.find_element(By.ID, 'userName')

Resources