Selenium Java遇StaleElementReferenceException,求解决及domPropertyToBe指导
StaleElementReferenceException 解决方案及 domPropertyToBe 用法咨询
问题本质
你遇到的org.openqa.selenium.StaleElementReferenceException,核心原因是代码中缓存的WebElement已经从DOM中被移除或重新渲染。在你的场景里,点击下拉箭头drpSem_Arrow后,下拉列表的<li>元素会被页面重新生成,而你提前获取的listElement列表中的元素引用已失效,后续循环点击时就会触发异常。
解决方案
1. 缩小定位范围+避免提前缓存元素
不要用By.tagName("li")这种全局定位,应该限定在下拉框容器内部查找<li>,同时不要提前缓存整个列表,每次循环都重新定位元素:
// 点击下拉箭头后,先等待下拉框容器可见 w.until(ExpectedConditions.visibilityOfElementLocated(By.id("drpSem_DropDown"))); // 循环查找目标元素,每次都重新获取列表 boolean found = false; while (!found) { List<WebElement> listElement = dChromedriver.findElements(By.xpath("//div[@id='drpSem_DropDown']//li")); for (WebElement list : listElement) { if (list.getText().equals("SY BTech - CSE / TRIMESTER-V / 2020-21 / Middle")) { w.until(ExpectedConditions.elementToBeClickable(list)); list.click(); // 重新获取show按钮,避免按钮因页面更新失效 WebElement showBtn = w.until(ExpectedConditions.elementToBeClickable(By.id("btnshow"))); showBtn.click(); found = true; break; } } }
2. 封装重试机制处理异常
如果页面频繁更新,可封装一个带重试逻辑的点击方法,捕获StaleElementReferenceException后重新尝试:
public static void clickWithRetry(WebDriver driver, WebDriverWait wait, By locator, int retryCount) { int attempts = 0; while (attempts < retryCount) { try { WebElement element = wait.until(ExpectedConditions.elementToBeClickable(locator)); element.click(); return; } catch (StaleElementReferenceException e) { attempts++; } } throw new RuntimeException("点击元素失败,已重试" + retryCount + "次"); }
使用时直接调用:
clickWithRetry(dChromedriver, w, By.xpath("//li[text()='SY BTech - CSE / TRIMESTER-V / 2020-21 / Middle']"), 3);
3. 优化等待逻辑
用elementToBeClickable代替visibilityOfAllElementsLocatedBy,因为元素可见不代表可交互,前者会等待元素处于稳定的可点击状态。
关于domPropertyToBe的用法
可以使用ExpectedConditions.domPropertyToBe()方法,它用于等待元素的某个DOM属性达到指定值,比如:
- 等待按钮的
disabled属性变为false(元素可点击):
w.until(ExpectedConditions.domPropertyToBe(By.id("btnshow"), "disabled", false));
- 等待输入框的
value属性为指定文本:
w.until(ExpectedConditions.domPropertyToBe(By.id("txtUserId"), "value", "S1032200787"));
不过针对你当前的列表点击问题,domPropertyToBe并非最优选择,elementToBeClickable已经包含了元素可见、可交互的检查,更直接适用。
修改后的完整代码示例
import java.time.Duration; import java.util.List; import org.openqa.selenium.By; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.chrome.ChromeDriver; import org.openqa.selenium.support.ui.ExpectedConditions; import org.openqa.selenium.support.ui.WebDriverWait; import org.testng.Assert; public class erp { public static void main(String[] args) throws InterruptedException { System.setProperty("webdriver.chrome.driver", "C:\\Tools\\Selenium\\Chromedriver96\\chromedriver_win32 (1)\\chromedriver.exe"); WebDriver dChromedriver = new ChromeDriver(); dChromedriver.get("https://erp.mitwpu.edu.in/"); dChromedriver.manage().window().maximize(); WebElement txtUserId = dChromedriver.findElement(By.id("txtUserId")); WebElement txtPassword = dChromedriver.findElement(By.id("txtPassword")); txtUserId.sendKeys("S1032200787"); txtPassword.sendKeys("FynS@3XbZH6ZMWH"); WebDriverWait w = new WebDriverWait(dChromedriver, Duration.ofSeconds(30)); w.until(ExpectedConditions.visibilityOfElementLocated(By.xpath("//div[@id='ReCaptchContainer']"))); dChromedriver.findElement(By.xpath("//div[@id='ReCaptchContainer']")).click(); w.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("label#lblMessage"))); WebElement success_lablElement = dChromedriver.findElement(By.cssSelector("label#lblMessage")); Assert.assertEquals(success_lablElement.getText(), "Success"); dChromedriver.findElement(By.id("btnLogin")).click(); WebElement resultWebElement = dChromedriver.findElement(By.xpath("//nav[@class=\"mt-2\"]/ul/li[12]/a[@href=\"Examination/Report/StudentGradeCardDetail.aspx?MENU_CODE=Web_Result\"]")); resultWebElement.click(); w.until(ExpectedConditions.frameToBeAvailableAndSwitchToIt(By.id("FrameContent"))); dChromedriver.findElement(By.id("drpSem_Arrow")).click(); // 循环查找目标元素,处理StaleElement异常 boolean foundTarget = false; int maxAttempts = 3; int attempts = 0; while (!foundTarget && attempts < maxAttempts) { try { w.until(ExpectedConditions.visibilityOfElementLocated(By.id("drpSem_DropDown"))); List<WebElement> listElement = dChromedriver.findElements(By.xpath("//div[@id='drpSem_DropDown']//li")); for (WebElement list : listElement) { if (list.getText().equals("SY BTech - CSE / TRIMESTER-V / 2020-21 / Middle")) { w.until(ExpectedConditions.elementToBeClickable(list)); list.click(); WebElement showBtn = w.until(ExpectedConditions.elementToBeClickable(By.id("btnshow"))); showBtn.click(); foundTarget = true; break; } } } catch (StaleElementReferenceException e) { attempts++; } } dChromedriver.quit(); } }
内容的提问来源于stack exchange,提问作者Avdhut Joshi
相关产品推荐
相关产品推荐

