【问题标题】:selenium <element is not attached to the page document" in selenium> Javaselenium <元素未附加到页面文档“在selenium> Java中
【发布时间】:2021-07-16 05:24:45
【问题描述】:

我正在尝试使用 Xpath 立即从活动元素中获取数据 但是当我运行这个项目时,我得到了这个错误

线程“main”org.openqa.selenium.StaleElementReferenceException 中的异常:过时的元素引用:元素未附加到页面文档

    package read;

    import java.util.concurrent.TimeUnit;
    import org.openqa.selenium.By;
    import org.openqa.selenium.WebDriver;
    import org.openqa.selenium.chrome.ChromeDriver;
    
    public class ResdeStoFromBrowser {
    
        public static final String TEXT_RESET = "\u001B[0m";
        public static final String TEXT_RED = "\u001B[31m";
        public static final String TEXT_GREEN = "\u001B[32m";
        public static final String TEXT_CYAN = "\u001B[36m";
    
        public void ResdeSto() throws InterruptedException {
            System.setProperty("webdriver.chrome.driver", "C:\\Users\\owner\\....\\chromedriver.exe");
            WebDriver driver = new ChromeDriver();
            driver.navigate().to("https:.........");
            driver.manage().window().maximize();
            while (true) {
                TimeUnit.SECONDS.sleep(1);
                String sel2 = driver.findElement(By.xpath("/html/body/div[2]/div[1]/div/div[2]/div[2]/div[2]/div[2]/div[1]/div[1]/span[3]")).getText();
                System.out.println(TEXT_GREEN + "  " + sel2 + TEXT_RESET + "    ");
            }
        }
    }

【问题讨论】:

  • 为什么最后会出现死循环?
  • 不断从源头获取数据!!
  • 这毫无意义,可能是个问题。
  • 能否添加HTML代码或网址
  • @Sonali 在帖子中添加 HTML 无济于事,因为页面内容会发生变化。

标签: java selenium xpath


【解决方案1】:

您写道“我正在尝试立即获取数据...”嗯,这可能是个问题。

StaleElementReferenceException在网页内容刷新前或刷新过程中获取到web元素时抛出。换句话说,它是过早获得的。解决方法是等到页面完全加载完毕。

“元素未附加到页面文档”表示该 Web 元素可能不再在 HTML 文档中。

获取网页元素有两种方式:

WebDriver driver = new ChromeDriver();
driver.findElement(...);

假设您在正确的页面上,findElement 将立即尝试定位元素。如果页面正在加载过程中,很可能会导致 OP 帖子中提到的错误。解决此问题的正确方法是添加隐式等待。

WebDriver driver = new ChromeDriver();
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS); // Time amount and time units are arbitrary.
// get to the page...
driver.findElement(...);

在上面的 sn-p 中,从调用 implicitlyWait 到测试会话结束,在任何尝试获取 web 元素之前,应用程序将等待最少的传递给函数的时间;在我的示例中是 10 秒。

更好的方法是使用WebDriverWait 类。

WebDriver driver = new ChromeDriver();
WebDriverWait wait = new WebDriverWait(driver, 10); // max. wait time set to 10 seconds with default 500 ms polling interval

WebDriverWait 有一个三参数变体,其中第三个参数是以毫秒为单位的轮询间隔。例如,WebDriverWait(driver, 10, 100) 将等待最多 10 秒,每 100 毫秒轮询一次。一旦获得wait 对象,它将用于获得WebElement 对象,该对象传递ExpectedConditions 类提供的正确预期条件。例如,等待按钮变为“可点击”(可见启用

WebDriver driver = new ChromeDriver();
WebDriverWait wait = new WebDriverWait(driver, 10);
WebElement button = wait.until(ExpectedConditions.elementToBeClickable(By.xpath(XPATH EXPRESSION HERE)));
button.click();

这种方法,假设您已经在正确的页面上,将尝试在传递给WebDriverWait 构造函数的最长时间内找到所需的组件,然后再超时。但是,如果组件被定位并且在超时之前达到了预期的条件,它将返回请求的组件。这是避免过时元素的更好方法(尽管不完全)。

可能最好的方法是将这两种方法结合起来。

首先,在获取 Web 驱动程序实例后立即设置隐式等待时间

WebDriver driver = new ChromeDriver();
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);

然后,导航到页面

driver.navigate().to("https:.........");

最后,使用第二种方式获取网页元素

WebDriverWait wait = new WebDriverWait(driver, 10);
WebElement button = wait.until(ExpectedConditions.elementToBeClickable(By.xpath("...")));
button.click();

当同时使用隐式和显式等待时,过时元素问题的可能性几乎降低到零。你只需要很聪明,并且总是在你要使用它之前获取网络元素......并且绝对不要将这样的代码放入无限循环中。

基本上,这段代码可以工作......有点。

public class TickerPageTest {
    @Test
    public void printTickerValueEndlessLoop() {
        System.setProperty("webdriver.chrome.driver", "F:\\Users\\Hector\\webdriver\\chromedriver.exe");
        WebDriver driver = new ChromeDriver();
        driver.manage().window().maximize();
        driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
        driver.get("https://coincheck.com/exchange/tradeview");
        
        while (true) {
        WebDriverWait wait = new WebDriverWait(driver, 10, 10);
        WebElement element = wait.until(ExpectedConditions.visibilityOfElementLocated(By.xpath("/html/body/div[2]/div[1]/div/div[2]/div[2]/div[2]/div[2]/div[1]/div[1]/span[3]")));
        System.out.println(element.getTagName() + ":" + element.getText());
        }
    }
}

上面的代码输出如下(大部分时间)

span:5898999
...
span:5900895
...
span:5898999

最好的办法是将与 web 元素的交互包装在 try/catch 中,您将在其中捕获 StaleElementReferenceException 以忽略它并继续。在真正的 Selenium 测试中,您可以使用此策略重试获取丢失的元素,但在这种情况下您不需要。

try {
    System.out.println(element.getTagName() + ":" + element.getText());
} catch (StaleElementReferenceException e) {
    System.err.println("Test lost sync... this will be ignored.");
}

当我这样做时,在几百行(或更多)之后,我能够发现同步丢失:

span:5906025
Test lost sync... this will be ignored.
span:5906249

但是,如您所见,我只是忽略了它并继续进行下一次更新。

【讨论】:

  • @DAROUYABDELKARIM 是您要公开测试的 URL 吗?如果是这样,请发布 URL。
  • 不知道你们国家能不能看到[coincheck.com/exchange/tradeview]
  • @DAROUYABDELKARIM 我知道你在做什么。但是,你应该明白我想说的是:页面不断刷新。这会很棘手。
  • 对不起我的无知,但是当你说棘手时,你是指 Enlegale 吗??
  • @DAROUYABDELKARIM 我建议的代码对我来说很好用。我会发帖的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-04-23
  • 1970-01-01
  • 2021-12-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多