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

如何在自定义Browser类中实现Selenium DevTools的getDevTools()方法

在自定义Browser类中实现Selenium DevTools获取功能

问题背景

使用Selenium 4.8时,直接实例化ChromeDriver可以轻松获取DevTools:

ChromeDriver driver = new ChromeDriver();
DevTools devTool = driver.getDevTools();
devTool.createSession();

但测试依赖自定义Browser类(代码如下),该类根据配置返回本地/远程WebDriver,现在需要在这个类中实现DevTools的获取能力,目标是支持以下调用方式:

WebDriver extendedDriver = Browser.extendedDriver();
DevTools devTool = extendedDriver.getDevTools();
devTool.createSession();

自定义Browser类代码

import lombok.extern.slf4j.Slf4j;
import <LOCAL ADDRESS REMOVED>.selenium.config.BrowserConfig;
import <LOCAL ADDRESS REMOVED>.selenium.config.SeleniumOptions;
import <LOCAL ADDRESS REMOVED>.selenium.driver.ExtendedWebDriver;
import <LOCAL ADDRESS REMOVED>.selenium.driver.WebDriverFactory;
import org.openqa.selenium.InvalidArgumentException;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.openqa.selenium.remote.LocalFileDetector;
import org.openqa.selenium.remote.RemoteWebDriver;
import org.openqa.selenium.support.ui.WebDriverWait;
import java.net.MalformedURLException;
import java.net.URL;
import java.security.InvalidParameterException;
import java.time.Duration;
import java.util.List;
import java.util.concurrent.TimeUnit;

import static java.lang.String.format;

@Slf4j
public class Browser {
    public static final int DEFAULT_IMPLICIT_WAIT = 0;
    public static final int DEFAULT_SCRIPT_TIMEOUT = 20;
    public static final int DEFAULT_WAIT_TIMEOUT = 30;
    public static long globalWaitTimeout;
    private static boolean useRemoteDriver = false;
    private static SeleniumOptions.WebAppTeknologi webAppTeknologi = SeleniumOptions.WebAppTeknologi.INGEN;
    private static ThreadLocal<WebDriver> driver=new ThreadLocal<>();
    private static ThreadLocal<ExtendedWebDriver> extendedDriver=new ThreadLocal<>();
    private static ThreadLocal<JavascriptExecutor> jsExecutor=new ThreadLocal<>();
    private static ThreadLocal<WebDriverWait> standardWait=new ThreadLocal<>();

    private Browser() {}

    public static void init(BrowserConfig browserConfig, List<String> chromeOptionsParameters) throws MalformedURLException {
        Browser.webAppTeknologi = browserConfig.getWebAppTeknologi();
        String seleniumGridUrl = browserConfig.getSeleniumGridAdresse();
        if (StringUtils.isNotBlank(seleniumGridUrl)) {
            for (int i = 0; i <= 5; i++) {
                try {
                    opprettEksternBrowser(browserConfig.getNettleserType(), new URL(seleniumGridUrl));
                    break;
                }
                catch (org.openqa.selenium.remote.UnreachableBrowserException unreachableBrowserException) {
                    log.debug(String.format("Klarte ikke starte browser mot %s på forsøk nr %s. Venter 10 s",seleniumGridUrl,i));
                    try {
                        TimeUnit.SECONDS.sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        } else {
            opprettLokalBrowser(browserConfig.getNettleserType(), chromeOptionsParameters);
        }

        setBrowserTimeouts(DEFAULT_SCRIPT_TIMEOUT, DEFAULT_IMPLICIT_WAIT, DEFAULT_WAIT_TIMEOUT);
    }

    private static void opprettLokalBrowser(SeleniumOptions.NettleserType browser, List<String> chromeOptionsParameters) {
        switch (browser) {
            case CHROME:
                final ChromeOptions chromeOptions = new ChromeOptions();

                if (chromeOptionsParameters != null) {
                    for (String parameter : chromeOptionsParameters) {
                        chromeOptions.addArguments(parameter);
                    }
                }

                driver.set(new ChromeDriver(chromeOptions));
                log.debug("Chrome valgt som ønsket nettleser.");
                break;
            case CHROME_HEADLESS:
                final ChromeOptions chromeOptions2 = new ChromeOptions();
                chromeOptions2.setHeadless(true);
                driver.set(new ChromeDriver(chromeOptions2));
                log.debug("Chrome Headless valgt som ønsket nettleser.");
                break;
            default:
                throw new InvalidArgumentException(format("Nettleser '%s' ikke implementert i rammeverk", browser.name()));
        }
    }

    private static void opprettEksternBrowser(SeleniumOptions.NettleserType browser, URL seleniumGridUrl) {
        useRemoteDriver = true;
        RemoteWebDriver remoteWebDriver;
        switch (browser) {
            case CHROME:
                final ChromeOptions chromeOptions = new ChromeOptions();
                remoteWebDriver = new RemoteWebDriver(seleniumGridUrl, chromeOptions);
                log.debug("Remote (Chrome) valgt som ønsket nettleser.");
                break;
            default:
                throw new InvalidParameterException(format("Nettleser %s for selenium grid ikke implementert i rammeverk", browser.name()));
        }
        remoteWebDriver.setFileDetector(new LocalFileDetector()); // For filopplasting fra lokal-path
        driver.set(remoteWebDriver);
    }

    public static void setBrowserTimeouts(int scriptTimeout, int implicitWait, int waitTimeout) {
        if (driver == null) {
            throw new NullPointerException("Browser.init() må kjøres før man kan kalle driver-instansen");
        }
        driver.get().manage().timeouts().setScriptTimeout(scriptTimeout, TimeUnit.SECONDS);
        driver.get().manage().timeouts().implicitlyWait(implicitWait, TimeUnit.SECONDS);
        globalWaitTimeout = (long) waitTimeout;
        standardWait.set(new WebDriverWait(driver.get(), Duration.ofSeconds(waitTimeout)));
    }

    public static WebDriver vanillaDriver() {
        if (driver.get() == null) {
            throw new NullPointerException("Browser.init() må kjøres før man kan kalle driver-instansen");
        }
        return driver.get();
    }

    public static ExtendedWebDriver extendedDriver() {
        if (extendedDriver.get() != null) {
            return extendedDriver.get();
        }
        if (getWebAppType().equals(SeleniumOptions.WebAppTeknologi.INGEN)) {
            throw new RuntimeException("Ingen WebAppTeknologi satt, bruk vanillaDriver() eller sett WebAppTeknologi");
        }
        extendedDriver.set(WebDriverFactory.getExtendedWebDriver(vanillaDriver(), webAppTeknologi));
        return extendedDriver.get();
    }

    public static JavascriptExecutor jsExecutor() {
        if (jsExecutor.get() == null) {
            WebDriver jsDriver = vanillaDriver();
            jsExecutor.set((JavascriptExecutor) jsDriver);
        }
        return jsExecutor.get();
    }

    public static WebDriverWait Wait() {
        if (standardWait.get() == null) {
            throw new NullPointerException("StandardWait er ikke satt");
        }
        return standardWait.get();
    }

    public static WebDriverWait Wait(long timeOutInSeconds) {
        return new WebDriverWait(vanillaDriver(), Duration.ofSeconds(timeOutInSeconds));
    }

    public static boolean isRemoteDriver() {
        return useRemoteDriver;
    }

    public static SeleniumOptions.WebAppTeknologi getWebAppType() {
        return webAppTeknologi;
    }

}

解决方案

步骤1:添加DevTools的线程安全存储

在Browser类的静态变量区新增ThreadLocal,保证多线程测试下的资源隔离:

import org.openqa.selenium.devtools.DevTools;
// ... 保留原有导入

private static ThreadLocal<DevTools> devTools = new ThreadLocal<>();

步骤2:实现getDevTools方法

在Browser类中新增获取DevTools的方法,兼容本地ChromeDriver和远程Chrome驱动:

public static DevTools getDevTools() {
    if (devTools.get() != null) {
        return devTools.get();
    }
    WebDriver currentDriver = vanillaDriver();
    DevTools devTool;

    // 处理本地ChromeDriver实例
    if (currentDriver instanceof ChromeDriver) {
        devTool = ((ChromeDriver) currentDriver).getDevTools();
    }
    // 处理远程Chrome驱动(Selenium 4+支持RemoteWebDriver直接获取DevTools)
    else if (currentDriver instanceof RemoteWebDriver && 
             currentDriver.getClass().getName().contains("Chrome")) {
        devTool = ((RemoteWebDriver) currentDriver).getDevTools();
    }
    // 不支持的浏览器类型抛出异常
    else {
        throw new UnsupportedOperationException("当前浏览器类型不支持DevTools功能");
    }

    devTool.createSession();
    devTools.set(devTool);
    return devTool;
}

步骤3:让ExtendedWebDriver支持直接调用

如果要通过Browser.extendedDriver().getDevTools()直接调用,需要修改自定义的ExtendedWebDriver接口:

public interface ExtendedWebDriver extends WebDriver {
    // ... 保留原有方法
    DevTools getDevTools();
}

然后在对应的实现类中实现该方法:

public class YourExtendedWebDriverImpl implements ExtendedWebDriver {
    // ... 保留原有实现
    @Override
    public DevTools getDevTools() {
        return Browser.getDevTools();
    }
}

可选:添加资源清理逻辑

在Browser类的quit方法中(如果已有)新增DevTools的清理代码,避免资源泄漏:

public static void quit() {
    // 清理DevTools资源
    if (devTools.get() != null) {
        devTools.get().close();
        devTools.remove();
    }
    // 清理其他驱动资源
    if (driver.get() != null) {
        driver.get().quit();
        driver.remove();
    }
    if (extendedDriver.get() != null) {
        extendedDriver.remove();
    }
    if (jsExecutor.get() != null) {
        jsExecutor.remove();
    }
    if (standardWait.get() != null) {
        standardWait.remove();
    }
}

使用方式

现在可以直接通过以下代码获取并使用DevTools:

ExtendedWebDriver extendedDriver = Browser.extendedDriver();
DevTools devTool = extendedDriver.getDevTools();
// 示例:启用网络拦截等DevTools功能
devTool.send(Network.enable(Optional.empty(), Optional.empty(), Optional.empty()));

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 18:22:01