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

Selenium 3切换Frame失效:如何无需重试机制修复?

Selenium Firefox驱动切换Frame后找不到元素的问题

登录后点击菜单选项卡中属于control frame的Switch按钮,页面加载完成后无法找到switchToProduction元素,驱动似乎仍关联旧的control frame。使用chromedriver及Selenium 2时一切正常,尝试过各种等待机制但问题未解决。

错误日志

console.warn: services.settings: Allow by setting MOZ_REMOTE_SETTINGS_DEVTOOLS=1 in the environment
console.error: (new TypeError("lazy.AsyncShutdown.profileBeforeChange is undefined", "resource://services-settings/Database.sys.mjs", 599))
Exception in thread "main" org.openqa.selenium.TimeoutException: Expected condition failed: waiting for presence of any elements located by By.id: switchToProduction (tried for 5 second(s) with 500 milliseconds interval)
    at org.openqa.selenium.support.ui.WebDriverWait.timeoutException(WebDriverWait.java:95)
    at org.openqa.selenium.support.ui.FluentWait.until(FluentWait.java:272)
    at test.Test2.main(Test2.java:39)
Caused by: org.openqa.selenium.NoSuchWindowException: Browsing context has been discarded
Build info: version: '3.141.59', revision: 'e82be7d358', time: '2018-11-14T08:17:03'
System info: host: 'uk2prdd21846', ip: '127.0.0.1', os.name: 'Linux', os.arch: 'amd64', os.version: '3.10.0-1160.102.1.el7.x86_64', java.version: '1.8.0_341'
Driver info: org.openqa.selenium.firefox.FirefoxDriver
Capabilities {acceptInsecureCerts: true, browserName: firefox, browserVersion: 115.4.0, javascriptEnabled: true, moz:accessibilityChecks: false, moz:buildID: 20231018093353, moz:geckodriverVersion: 0.33.0, moz:headless: false, moz:platformVersion: 3.10.0-1160.102.1.el7.x86_64, moz:processID: 8735, moz:profile: /tmp/rust_mozprofile11C1Wj, moz:shutdownTimeout: 60000, moz:useNonSpecCompliantPointerOrigin: false, moz:webdriverClick: true, moz:windowless: false, pageLoadStrategy: normal, platform: LINUX, platformName: LINUX, proxy: Proxy(), setWindowRect: true, strictFileInteractability: false, timeouts: {implicit: 0, pageLoad: 300000, script: 30000}, unhandledPromptBehavior: dismiss and notify}
Session ID: 769f8749-d169-4169-a0e0-bf4fcc429ea1
*** Element info: {Using=id, value=switchToProduction}
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
    at org.openqa.selenium.remote.http.W3CHttpResponseCodec.createException(W3CHttpResponseCodec.java:187)
    at org.openqa.selenium.remote.http.W3CHttpResponseCodec.decode(W3CHttpResponseCodec.java:122)
    at org.openqa.selenium.remote.http.W3CHttpResponseCodec.decode(W3CHttpResponseCodec.java:49)
    at org.openqa.selenium.remote.HttpCommandExecutor.execute(HttpCommandExecutor.java:158)
    at org.openqa.selenium.remote.service.DriverCommandExecutor.execute(DriverCommandExecutor.java:83)
    at org.openqa.selenium.remote.RemoteWebDriver.execute(RemoteWebDriver.java:552)
    at org.openqa.selenium.remote.RemoteWebDriver.findElements(RemoteWebDriver.java:353)
    at org.openqa.selenium.remote.RemoteWebDriver.findElementsById(RemoteWebDriver.java:376)
    at org.openqa.selenium.By$ById.findElements(By.java:180)
    at org.openqa.selenium.remote.RemoteWebDriver.findElements(RemoteWebDriver.java:311)
    at org.openqa.selenium.support.ui.ExpectedConditions$11.apply(ExpectedConditions.java:328)
    at org.openqa.selenium.support.ui.ExpectedConditions$11.apply(ExpectedConditions.java:325)
    at org.openqa.selenium.support.ui.FluentWait.until(FluentWait.java:249)

使用环境

  • Selenium 3.141.59
  • geckodriver 0.33
  • Firefox 113

测试代码

System.setProperty("webdriver.gecko.driver", "geckodriver");
//        System.setProperty("webdriver.chrome.driver", "chromedriver");

FirefoxOptions options = new FirefoxOptions();
options.setLogLevel(Level.FINEST);
WebDriver driver = new FirefoxDriver(options);

driver.get("myurl");

//login
driver.findElement(By.id("username")).sendKeys("user");
driver.findElement(By.name("password")).sendKeys("password");
driver.findElement(By.id("login")).click();

WebDriverWait wait = new WebDriverWait(driver, 5);

//click Switch button from control frame
driver.switchTo().defaultContent();
wait.until(ExpectedConditions.frameToBeAvailableAndSwitchToIt(By.id("control")));
wait.until(ExpectedConditions.elementToBeClickable(By.id("switchToTest")));
driver.findElement(By.id("switchToTest")).click();

//check that after Switch button is pressed, Switch to Production button is present in "control" frame
driver.switchTo().defaultContent();
wait.until(ExpectedConditions.frameToBeAvailableAndSwitchToIt(By.id("control")));
wait.until(ExpectedConditions.presenceOfAllElementsLocatedBy(By.id("switchToProduction")));

driver.quit();
}
}

pom.xml配置

<dependencies>
    <dependency>
        <groupId>org.seleniumhq.selenium</groupId>
        <artifactId>selenium-java</artifactId>
        <version>3.141.59</version>
    </dependency>

    <dependency>
        <groupId>org.seleniumhq.selenium</groupId>
        <artifactId>selenium-api</artifactId>
        <version>3.141.59</version>
    </dependency>
    <dependency>
        <groupId>org.seleniumhq.selenium</groupId>
        <artifactId>selenium-support</artifactId>
        <version>3.141.59</version>
    </dependency>
</dependencies>
<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <configuration>
                <source>8</source>
                <target>8</target>
            </configuration>
        </plugin>
    </plugins>
</build>

解决方案

错误提示中的Browsing context has been discarded说明点击Switch按钮后,原有的control frame上下文已被销毁,Firefox重新渲染了frame,此时直接切换会关联旧的失效上下文。可以通过以下步骤修复:

  1. 延长等待时间并等待页面完全加载:点击Switch按钮后,先等待页面的document.readyState变为complete,确保页面所有资源加载完成。
  2. 重新获取frame上下文:切换到defaultContent后,使用更长的等待时间确保新的control frame完全可用。
  3. 等待元素可见而非仅存在:visibilityOfElementLocated比presenceOfAllElementsLocatedBy更可靠,能确保元素已渲染完成。

修改后的代码片段:

// 点击Switch按钮后,等待页面完全加载
wait.until(ExpectedConditions.jsReturnsValue("return document.readyState === 'complete'"));

// 切换回默认上下文,重新获取control frame
driver.switchTo().defaultContent();
// 延长等待时间到10秒,适配Firefox的渲染速度
WebDriverWait longerWait = new WebDriverWait(driver, 10);
longerWait.until(ExpectedConditions.frameToBeAvailableAndSwitchToIt(By.id("control")));
// 等待元素可见
longerWait.until(ExpectedConditions.visibilityOfElementLocated(By.id("switchToProduction")));

另外,也可以尝试通过frame的其他属性(如name、xpath)定位,避免仅依赖id导致的定位问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 05:25:55