仅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中获取链接元素,避免使用失效的元素引用。具体调整如下:
- 先获取页脚链接的总数量,通过索引循环遍历
- 每次循环都重新定位当前索引对应的链接元素
- 优化滚动和等待逻辑,避免依赖失效的
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
相关产品推荐
相关产品推荐

