如何使用 Selenium 单击多个元素同时避免陈旧元素错误

How to use Selenium to click through multiple elements while avoiding Stale Element Error

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

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

到目前为止,这是我的代码(问题出在 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 工作,但在 java/selenium 工作过。但是,我可以给你克服陈旧的想法。

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

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

示例:

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

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

String xpath = "//*[@id='Whosebug']";
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 变量不是星号,它是所需元素的 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()