python - 如何解决陈旧的元素参考 - Selenium(Python)
问题描述
我知道这个问题已被多次问过,但我似乎无法将任何解决方案应用于我自己的情况。
我正在为某些值抓取网站,但是,这些值存在于网站上的不同配置文件中。因此,我登录、检索值、注销、在新配置文件下重新登录、检索值、注销等。
问题在于似乎正在生成陈旧元素引用的悬停菜单项之一。我认为这是由于我退出并重新登录造成的?这可以解决还是我应该只启动一个新的 WebDriver 实例?
到目前为止,这是我的代码,请记住我对 Python 很陌生,所以请原谅任何愚蠢的错误或假设:
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)
请参阅下面的堆栈跟踪:
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
解决方案
如果你看源代码
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
if element and element.is_enabled():
该元素可能在位于上一行(visibility_of_element_located
句柄)之后变得陈旧StaleElementReferenceException
。你可以加ignored_exceptions=[StaleElementReferenceException]
减速WebDriverWait
来解决这个问题
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")))
还有几点:
- 有
frame_to_be_available_and_switch_to_it
处理帧的预期条件 - Python 变量应该全部小写
你有代码重复,你可以使用函数来代替
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()
编辑:
根据您添加的堆栈跟踪,异常实际上是 on actions.move_to_element(Investment1).perform()
。可以通过简单的循环和重试来解决
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
推荐阅读
- mongodb - 仅从 mongodb 返回数组中的命中
- ruby - 理解在 Ruby 中调用变量
- javascript - Vuejs2 手表不适用于来自 ajax 调用的数据
- go - 带有代理中间件的 Echo CORS 导致带有 Access-Allow-Origins 响应标头的问题
- apache-flink - 如何从作业(应用程序)中读取 apache flink jobmanager 配置
- python - 当一个被省略时会发生什么初始化
- nginx - NGINX 无法将 https POST 请求转发到另一个端口
- python - 将类中的方法存储在新文件中
- regex - Python regex 错误:look-behind 需要固定宽度的模式
- javascript - 嵌套数组对象与另一个元素数组进行比较并使用 Javascript 或 ES6 创建新数组