You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

仅FireFox与Safari出现StaleElementReferenceException问题求助

问题

需要实现以下操作:

  • 滚动页面使页脚进入视口
  • 获取页脚所有链接元素存入列表
  • 遍历列表点击每个链接,跳转后判断页面URL是否包含链接文本前3个字符
  • 返回首页重复上述流程

已使用滚动和显式等待方法,但点击第一个链接返回首页后,FireFox和Safari中出现StaleElementReferenceException异常,Chrome中运行正常。期望代码能跨浏览器无错误处理所有链接。

原代码如下:

import org.openqa.selenium.*;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.safari.SafariDriver;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
import java.time.Duration;
import java.util.List;

public class Assignment9 {
    public static void main(String[] args) throws InterruptedException {
        ChromeOptions co= new ChromeOptions();
        co.addArguments("--remote-allow-origins=*");
        // WebDriver driver= new ChromeDriver(co);
        WebDriver driver = new FirefoxDriver();
        driver.manage().window().maximize();
        driver.manage().deleteAllCookies();
        driver.manage().timeouts().pageLoadTimeout(Duration.ofSeconds(40));
        driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(30));
        driver.get("https://fueled.com/en-gb");
        
        WebElement footer= driver.findElement(By.xpath("//div[@id='app']/child::div[last()]"));
        List<WebElement> li= driver.findElements(By.xpath("//footer//ul[1]/li/a"));
        
        for(WebElement ele: li){
            try {
                waits(driver, ele, Duration.ofSeconds(80));
            }catch (TimeoutException e){
                waits(driver, ele, Duration.ofSeconds(80));
            }
            String linkText= ele.getText();
            String linkText1=linkText.substring(0, 3).toLowerCase();
            
            ele.click();
            String pageUrl=driver.getCurrentUrl();
            System.out.println(pageUrl);
            if(pageUrl.contains(linkText1)){
                System.out.println(linkText + " is navigating to correct page");
            }else {
                System.out.println("Not a correct page");
            }
            
            driver.navigate().back();
            System.out.println("back to home page");
            scroll(driver, footer, Duration.ofSeconds(40));
            System.out.println("page has scrolled down");
        }
    }
    
    static void scroll(WebDriver driver, WebElement element, Duration timeout) {
        WebElement element1=driver.findElement(By.xpath("//div[@id='app']/child::div[last()]"));
        new WebDriverWait(driver, timeout).ignoring(StaleElementReferenceException.class)
            .until(ExpectedConditions.visibilityOfElementLocated(By.xpath("//div[@id='app']/child::div[last()]")));
        JavascriptExecutor js = (JavascriptExecutor) driver;
        js.executeScript("arguments[0].scrollIntoView(true);", element1);
    }
    
    static void waits(WebDriver driver, WebElement element, Duration timeout) throws TimeoutException {
        WebElement footer= driver.findElement(By.xpath("//div[@id='app']/child::div[last()]"));
        scroll(driver, footer, Duration.ofSeconds(30));
        WebDriverWait wait= new WebDriverWait(driver, timeout);
        wait.ignoring(StaleElementReferenceException.class).until(ExpectedConditions.elementToBeClickable(element));
    }
}
解决方案

异常原因

StaleElementReferenceException是因为从其他页面返回首页后,原页面的DOM已重新渲染,最初获取的List<WebElement>中的元素引用已经失效,无法再与当前DOM中的元素绑定。Chrome可能因DOM缓存机制未触发该异常,但FireFox和Safari会严格校验元素引用有效性。

修复方案

核心思路是每次返回首页后,重新从当前DOM中获取链接元素,避免使用失效的元素引用。具体调整如下:

  1. 先获取页脚链接的总数量,通过索引循环遍历
  2. 每次循环都重新定位当前索引对应的链接元素
  3. 优化滚动和等待逻辑,避免依赖失效的footer元素引用

修改后的代码:

import org.openqa.selenium.*;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.safari.SafariDriver;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
import java.time.Duration;

public class Assignment9 {
    public static void main(String[] args) {
        ChromeOptions co= new ChromeOptions();
        co.addArguments("--remote-allow-origins=*");
        // WebDriver driver= new ChromeDriver(co);
        WebDriver driver = new FirefoxDriver();
        driver.manage().window().maximize();
        driver.manage().deleteAllCookies();
        driver.manage().timeouts().pageLoadTimeout(Duration.ofSeconds(40));
        driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(30));
        driver.get("https://fueled.com/en-gb");

        // 先获取链接总数,后续按索引遍历
        scrollToFooter(driver);
        int linkCount = driver.findElements(By.xpath("//footer//ul[1]/li/a")).size();

        for(int i=0; i<linkCount; i++){
            // 每次循环重新获取当前索引的链接元素
            scrollToFooter(driver);
            WebElement currentLink = new WebDriverWait(driver, Duration.ofSeconds(20))
                    .ignoring(StaleElementReferenceException.class)
                    .until(ExpectedConditions.elementToBeClickable(By.xpath("//footer//ul[1]/li["+(i+1)+"]/a")));

            String linkText = currentLink.getText();
            String linkTextPrefix = linkText.substring(0, 3).toLowerCase();

            currentLink.click();
            String pageUrl = driver.getCurrentUrl();
            System.out.println(pageUrl);
            if(pageUrl.contains(linkTextPrefix)){
                System.out.println(linkText + " 跳转至正确页面");
            }else {
                System.out.println("跳转页面不正确");
            }

            // 返回首页后等待页面加载完成
            driver.navigate().back();
            System.out.println("返回首页");
            // 等待首页DOM重新稳定
            new WebDriverWait(driver, Duration.ofSeconds(20))
                    .until(ExpectedConditions.visibilityOfElementLocated(By.xpath("//div[@id='app']")));
        }
        driver.quit();
    }

    static void scrollToFooter(WebDriver driver) {
        WebElement footer = new WebDriverWait(driver, Duration.ofSeconds(20))
                .until(ExpectedConditions.visibilityOfElementLocated(By.xpath("//div[@id='app']/child::div[last()]")));
        JavascriptExecutor js = (JavascriptExecutor) driver;
        js.executeScript("arguments[0].scrollIntoView({behavior: 'smooth', block: 'end'});", footer);
    }
}

关键优化点

  • 按索引遍历链接,每次都从当前DOM中重新定位元素,彻底避免失效引用
  • 简化滚动逻辑,直接封装为scrollToFooter方法,每次滚动都重新获取最新的footer元素
  • 返回首页后增加等待,确保DOM完全加载稳定后再进行下一次操作
  • 移除冗余的等待重试逻辑,合并到显式等待中

内容的提问来源于stack exchange,提问作者aaryan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 08:14:59