python - 如何解决过时的元素引用 - Selenium(Python)

标签 python css selenium selenium-webdriver

我知道这个问题已被多次询问,但我似乎无法将任何解决方案应用于我自己的情况。

我正在抓取网站的某些值,但是,这些值存在于网站上的不同配置文件中。因此,我登录、检索值、注销、在新配置文件下重新登录、检索值、注销等。

问题出在悬停菜单项之一上,它似乎生成了过时的元素引用。我认为这是由于我注销并重新登录造成的?这是否可以修复,或者我应该只启动一个新的 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

最佳答案

如果您查看 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

该元素可能在 if element and element.is_enabled(): 位于上一行之后变得陈旧(visibility_of_element_located 处理 StaleElementReferenceException ).可以在WebDriverWait的减速中加入ignored_exceptions=[StaleElementReferenceException]来解决这个问题

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")))

补充几点:

  1. 存在处理帧的预期条件frame_to_be_available_and_switch_to_it
  2. Python变量应该全部小写
  3. 代码重复,可以用函数代替

    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()
    

编辑:

根据您添加的堆栈跟踪,异常实际上发生在 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

关于python - 如何解决过时的元素引用 - Selenium(Python),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55256213/

相关文章:

html - CSS 使特定的图像出现在特定的导航栏悬停上

css - 在 IE 8 及以下版本中拉伸(stretch)背景图像

python - selenium python 点击​​元素没有任何反应

javascript - selenium-webdriver 在 JavaScript 中找不到驱动程序?

python - 在 openpyxl 中将 x 轴标签设置为底部

python - 为什么 `finally: return` 不传播未处理的异常?

python - 机枪蜜蜂涉及 paramiko 语法错误。 (self._close(async=True))

python - 如何正确抓取基于 JavaScript 的网站?

jQuery animate scrolltop 它不工作

java - @BeforeMethod/@AfterMethod(onlyForGroups)方法没有执行,如果执行属于该组的测试方法