【问题标题】:How to use Selenium to click through multiple elements while avoiding Stale Element Error如何使用 Selenium 单击多个元素,同时避免 Stale Element Error
【发布时间】:2017-06-19 12:43:46
【问题描述】:

我正在制作一些站点地图/树(使用 anytree),为此,我需要 Selenium 在页面上找到特定元素(代表类别),然后系统地点击这些元素,查看为每个新页面上的新类别,直到我们没有更多的类别,即。所有叶子和树都被填充。

我已经写了很多。尝试遍历我的元素列表时出现了我的问题。我目前尝试先填充树的深度,向下到叶子,然后弹回原始页面以对列表中的下一个元素继续相同的操作。但是,这会导致 Stale element reference 错误,因为我的页面会重新加载。对此有什么解决方法?我可以以某种方式在新窗口中打开新链接以保留旧页面吗?我为该异常找到的唯一修复是巧妙地捕获它,但这对我没有帮助。

到目前为止,这是我的代码(问题在于 for 循环):

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
from anytree import Node, RenderTree

def findnodes(driver) :
    driver.implicitly_wait(5)
    try:
        nodes = driver.find_elements_by_css_selector('h3.ng-binding')
    except:
        nodes = []
    return nodes

def populateTree(driver, par) :

    url = driver.current_url
    pages = findnodes(driver)
    if len(pages)>0 :
        for page in pages:
            print(page.text)
            Node(page.text, parent=par)
            page.click()
            populateTree(driver, page.text)
            driver.get(url)

driver = webdriver.Chrome()
#Get starting page
main ='http://www.example.com'
root = Node(main)
driver.get(main)

populateTree(driver, root)

for pre, fill, node in RenderTree(root):
    print("%s%s" % (pre, node.name))

【问题讨论】:

    标签: python selenium selenium-webdriver anytree


    【解决方案1】:

    我没有在 python 中工作过,但在 java/selenium 上工作过。但是,我可以给你一个克服陈旧的想法。

    通常,如果在启动 web 元素后元素属性或某些内容发生更改,我们将收到 Stale Exception。例如,在某些情况下,如果用户尝试单击同一页面上的同一元素,但在页面刷新后,会出现 staleelement 异常。

    为了克服这个问题,我们可以创建新的 web 元素,以防页面发生更改或刷新。下面的代码可以给你一些想法。(它在java中,但概念是一样的)

    示例:

     webElement element = driver.findElement(by.xpath("//*[@id='StackOverflow']"));
     element.click();
     //page is refreshed
     element.click();//This will obviously throw stale exception
    

    为了克服这个问题,我们可以将 xpath 存储在一些字符串中,并使用它创建一个新的 web 元素。

    String xpath = "//*[@id='StackOverflow']";
    driver.findElement(by.xpath(xpath)).click();
    //page has been refreshed. Now create a new element and work on it
    driver.findElement(by.xpath(xpath)).click();   //This works
    

    希望对你有所帮助。

    【讨论】:

    • 感谢您的帮助,尽管这不是您的语言!我很感激。我理解为什么会出现陈旧错误,但我正在查找元素列表并尝试遍历它们,而您的示例只是重新查找特定元素(如果我没看错的话)。如果你有一个元素列表要检查,你怎么能在没有陈旧的阻碍的情况下做到这一点?
    • 再次使用 xpath 类似地重建元素列表。
    【解决方案2】:

    xpath 变量不应该是星号,它是所需元素的 xpath。出现过时的异常,因为我们在浏览器中单击了某些内容。这需要在每次单击时找到所有元素。所以在每个循环中,我们找到所有元素 driver.find_elements_by_xpath(xpath)。我们得到一个元素列表。但是我们只需要其中之一。因此,我们采用特定索引处的元素表示 idx,其范围从 0 到元素数。

    xpath = '*'
    for idx, _ in enumerate(range(len(driver.find_elements_by_xpath(xpath)))):
        element = driver.find_elements_by_xpath(xpath)[idx]
        element.click()
    

    【讨论】:

    • 当有人要求解释代码时,只回答最好编辑答案以包含该解释。这样可以提高答案的质量,如果有问题的答案在审核队列中,编辑可以帮助将其标记为“看起来不错”而不是删除。
    猜你喜欢
    • 1970-01-01
    • 2017-05-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-01
    • 1970-01-01
    • 1970-01-01
    • 2023-01-16
    相关资源
    最近更新 更多