Reputation: 101
I know this question has been asked multiple times but I cannot seem to apply any of the resolutions to my own situation.
I am scraping a website for certain values, however, the values exist on different profiles on the website. Therefore, I log in, retrieve a value, log out, log back in under a new profile, retrieve a value, log out etc.
The issue is on one of the hover menu items which seem to be generating a stale element reference. I assume this is due to me logging out and back in again? Is this possible to fix or should I rather just start a new WebDriver instance?
Here is my code so far, bear in my that I am very new to Python so forgive any silly errors or assumptions:
from selenium import webdriver
from selenium.webdriver.support import ui
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver import ActionChains
from selenium.common.exceptions import StaleElementReferenceException
options = Options()
options.add_argument("start-maximized")
driver = webdriver.Chrome(options=options, executable_path=r'C:/Users/SChogle/Downloads/chromedriver.exe')
actions = ActionChains(driver)
driver.get("xxxxx")
iframe = ui.WebDriverWait(driver, 10).until(EC.visibility_of_element_located((By.TAG_NAME, "iframe")))
driver.switch_to.frame(iframe)
driver.find_element_by_id("Username").send_keys("xxxx")
driver.find_element_by_id("Password").send_keys("xxxx")
driver.find_element_by_id("submit_button").click()
driver.switch_to.default_content()
Investment = WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.CSS_SELECTOR, "div.menu.menuTopCenter > ul > li:nth-child(3) > a")))
actions.move_to_element(Investment).perform()
Investment_Summary = (WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.CSS_SELECTOR,"li:nth-child(3) > div > div:nth-child(1) > a")))).click()
Imp_Prov = WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.CSS_SELECTOR, "div#product-UT td.portfolioProductContractFundHeaderValueRight"))).get_attribute('innerHTML').strip()
print(Imp_Prov)
#log-out
log_out = WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.CSS_SELECTOR, "a#btnLogoff"))).click()
#log back in
iframe = ui.WebDriverWait(driver, 10).until(EC.visibility_of_element_located((By.TAG_NAME, "iframe")))
driver.switch_to.frame(iframe)
driver.find_element_by_id("Username").send_keys("xxxx")
driver.find_element_by_id("Password").send_keys("xxxx")
driver.find_element_by_id("submit_button").click()
driver.switch_to.default_content()
tries = 0
while tries < 3:
try:
Investment = WebDriverWait(driver, 10,).until(EC.element_to_be_clickable((By.CSS_SELECTOR, "div.menu.menuTopCenter > ul > li:nth-child(3) > a")))
actions.move_to_element(Investment).perform()
tries = 3
except StaleElementReferenceException:
tries += 1
Investment_Summary1 = (WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.CSS_SELECTOR,"li:nth-child(3) > div > div:nth-child(1) > a")))).click()
Imp_Pen = WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.CSS_SELECTOR, "div#product-UT td.portfolioProductContractFundHeaderValueRight"))).get_attribute('innerHTML').strip()
print(Imp_Pen)
See stacktrace below:
174,256,175.68 ZAR
Traceback (most recent call last):
File "C:/Users/SChogle/PycharmProjects/test1/venv/Web Scraping - BCI.py", line 60, in <module>
Investment_Summary1 = (WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.CSS_SELECTOR,"li:nth-child(3) > div > div:nth-child(1) > a")))).click()
File "C:\Users\SChogle\PycharmProjects\test1\venv\lib\site-packages\selenium\webdriver\support\wait.py", line 80, in until
raise TimeoutException(message, screen, stacktrace)
selenium.common.exceptions.TimeoutException: Message:
Process finished with exit code 1
Upvotes: 3
Views: 1051
Reputation: 26
Try using -
Upvotes: 0
Reputation: 50864
If you look at the source code
class element_to_be_clickable(object):
""" An Expectation for checking an element is visible and enabled such that you can click it."""
def __init__(self, locator):
self.locator = locator
def __call__(self, driver):
element = visibility_of_element_located(self.locator)(driver)
if element and element.is_enabled():
return element
else:
return False
The element probably became stale before if element and element.is_enabled():
after being located in the previous line (visibility_of_element_located
handles StaleElementReferenceException
). You can add ignored_exceptions=[StaleElementReferenceException]
to the deceleration of WebDriverWait
to solve this
Investment1 = WebDriverWait(driver, 10, ignored_exceptions=[StaleElementReferenceException]).until(EC.element_to_be_clickable((By.CSS_SELECTOR, "div.menu.menuTopCenter > ul > li:nth-child(3) > a")))
Some more points:
frame_to_be_available_and_switch_to_it
to handle framesYou have code repetition, you can use functions instead
options = Options()
options.add_argument("start-maximized")
driver = webdriver.Chrome(options=options,
executable_path=r'C:/Users/SChogle/Downloads/chromedriver.exe')
actions = ActionChains(driver)
driver.get("xxxxxxx")
def do_login():
WebDriverWait(driver, 10).until(EC.frame_to_be_available_and_switch_to_it((By.TAG_NAME, "iframe")))
driver.find_element_by_id("Username").send_keys("xxxxx")
driver.find_element_by_id("Password").send_keys("xxxxx")
driver.find_element_by_id("submit_button").click()
driver.switch_to.default_content()
def print_content():
investment = WebDriverWait(driver, 10, ignored_exceptions=[StaleElementReferenceException]).until(EC.element_to_be_clickable((By.CSS_SELECTOR, "div.menu.menuTopCenter > ul > li:nth-child(3) > a")))
actions.move_to_element(investment).perform()
investment_summary = WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.CSS_SELECTOR,"li:nth-child(3) > div > div:nth-child(1) > a"))).click()
imp_prov = WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.CSS_SELECTOR, "div#product-UT td.portfolioProductContractFundHeaderValueRight"))).get_attribute('innerHTML').strip()
print(imp_prov)
do_login()
print_content()
driver.find_element_by_css_selector("a#btnLogoff").click()
do_login()
print_content()
Edit:
According to the stacktrace you added the exception is actually on actions.move_to_element(Investment1).perform()
. It can be solved by simple loop and retry
tries = 0
while tries < 3:
try:
investment = WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.CSS_SELECTOR, "div.menu.menuTopCenter > ul > li:nth-child(3) > a")))
actions.move_to_element(investment).perform()
tries = 3
except StaleElementReferenceException:
tries += 1
Upvotes: 2