使用 ChromeDriver 和 Chrome DevTools 协议进行多客户端远程调试

Posted

技术标签:

【中文标题】使用 ChromeDriver 和 Chrome DevTools 协议进行多客户端远程调试【英文标题】:Multi-client remote debugging using ChromeDriver and Chrome DevTools protocol 【发布时间】:2018-04-16 22:20:17 【问题描述】:

Chrome 63 现在支持多客户端远程调试 (https://developers.google.com/web/updates/2017/10/devtools-release-notes)

我想要实现的是使用 Chrome DevTools 协议 HeapProfiler 和一些硒测试。我正在运行 64 版 Chrome 开发通道和 ChromeDriver 2.33。

ChromeOptions options = newChromeOptions();
options.addArguments("--remote-debugging-port=9222");
WebDriver driver = new ChromeDriver(options);
... selenium stuff

一个新的 chrome 窗口将打开并挂起,直到超时。我可以通过帮助 > 关于 google chrome 检查版本来确认打开的 chrome 窗口是 chrome 64。 我收到此错误,这似乎是 webdriver 失去连接。

Exception in thread "main" org.openqa.selenium.WebDriverException: chrome not 
reachable

DevTools 协议正在运行,因为我可以在另一个 chrome 窗口中打开 http://localhost:9222 并查看调试界面。

有没有人能够让这两个东西一起工作?

谢谢:)

【问题讨论】:

调试地址需要作为选项提供,而不是参数。 嗨弗洛伦特。你知道它会是哪个选项吗?我在这里找到了一个列表src.chromium.org/viewvc/chrome/trunk/src/chrome/common/… sites.google.com/a/chromium.org/chromedriver/capabilities @FlorentB。给出了最好的答案。 【参考方案1】:

这里的问题是,如果您通过“remote-debugging-port”开关,那么 chromedriver 有一个错误,它仍然在内部分配一个随机端口并继续尝试连接到它而不是连接到 9222 端口。

options.addArguments("--remote-debugging-port=9222");

我们可以通过跳过这个命令开关来解决这个问题,让 chrome 决定这个随机端口并从 chromedriver 日志中提取这个端口号。

我成功了,在这里我详细地写了博客。

https://medium.com/@sahajamit/selenium-chrome-dev-tools-makes-a-perfect-browser-automation-recipe-c35c7f6a2360

【讨论】:

【参考方案2】:

Selenium 4 版本将为 Chrome DevTools 协议提供用户友好的 API。我刚刚为 Selenium Java 客户端实现了网络和性能域。 https://github.com/SeleniumHQ/selenium/pull/7212

此外,Java 客户端中的所有域都有一个通用 API,该 API 不久前被合并。所有这些新功能都可能在下一个 Alpha 版本中发布。

这是一篇关于如何使用 Log 的好文章: https://codoid.com/selenium-4-chrome-devtools-log-entry-listeners/

【讨论】:

【参考方案3】:

这是我为获取远程调试所需的信息以及另外防止定义端口所做的工作。我通过 SeleniumLog-API 得到它

DesiredCapabilities capabilities = DesiredCapabilities.chrome();
ChromeOptions options = new ChromeOptions();
options.setBinary(chromeBin);
capabilities.setCapability(ChromeOptions.CAPABILITY, options);
LoggingPreferences logPref = new LoggingPreferences();
logPref.enable(LogType.DRIVER, Level.ALL);
driverInstance = new ChromeDriver(capabilities);

LogEntries x = driverInstance.manage().logs().get(LogType.DRIVER);
    for(LogEntry e:x.getAll())
        if(e.getMessage().contains("DevTools request:"))
            String url = e.getMessage().replaceFirst("DevTools request:", "").trim();
        

        if(e.getMessage().contains("DevTools response:"))
            String json = e.getMessage().replaceFirst("DevTools response:", "");
            try 
                if("page".equals(JSONUtil.get(json,"type" )))
                    webSocketDebuggerUrl = JSONUtil.get(json,"webSocketDebuggerUrl" );
                
             catch (Exception e1) 
                e1.printStackTrace();
            

        
        System.out.println(e.getMessage());
    

我使用的 JSONUtil 是我自己的工具,所以不要怀疑,只需替换为从 jsontext 中提取的任何代码即可。

【讨论】:

【参考方案4】:

这是一个相当健壮的 java 实现,使用与 selenium 3.13 和 cdp4j 3.0.2-SNAPSHOT 相同的目标选项卡。轻松翻译成任何语言。

package com.company;

import com.google.gson.JsonElement;
import com.google.gson.JsonParser;
import io.webfolder.cdp.session.SessionFactory;
import org.openqa.selenium.HasCapabilities;
import org.openqa.selenium.Keys;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeDriverService;

import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Map;

public class Main 

    public static void main(String[] args) 

        System.setProperty(ChromeDriverService.CHROME_DRIVER_EXE_PROPERTY, "C:\\path\\to\\chromedriver.exe");
        var driver = new ChromeDriver();

        try 
            var cdp = findCdpEndpoint(driver);
            System.out.println(cdp.toString());
            try (var factory = new SessionFactory(cdp.getPort())) 
                driver.navigate().to("https://google.com");
                String seTargetId = getSeTargetId(cdp, driver.getTitle());

                try (var session = factory.connect(seTargetId)) 
                    session.waitDocumentReady();
                    session.sendKeys("Astronauts");
                    driver.getKeyboard().sendKeys(Keys.RETURN);
                    session.wait(2000);
                    driver.navigate().to("http://www.google.com");
                    session.waitDocumentReady();
                
            
         catch (Exception ex) 
            System.out.println(ex.toString());
        

        driver.quit();
    

    private static String getSeTargetId(URL cdp, String title) throws IOException 
        for (JsonElement element : new JsonParser().parse(new InputStreamReader(cdp.openStream(), "UTF-8")).getAsJsonArray()) 
            var object = element.getAsJsonObject();
            if (title == null || title.isEmpty()
                    ? object.get("type").getAsString().equalsIgnoreCase("page")
                    : object.get("title").getAsString().equalsIgnoreCase(title)) 
                return object.get("id").getAsString();
            
        
        throw new IllegalStateException("Selenium target not found.");
    

    private static URL findCdpEndpoint(WebDriver driver) throws IOException 
        var capChrome = (Map<?,?>) ((HasCapabilities)driver).getCapabilities().getCapability("chrome");
        var userDataDir = (String) capChrome.get("userDataDir");
        var port = Integer.parseInt(Files.readAllLines(Paths.get(userDataDir, "DevToolsActivePort")).get(0));
        return new URL("http", "localhost", port, "/json");
    

【讨论】:

以上是关于使用 ChromeDriver 和 Chrome DevTools 协议进行多客户端远程调试的主要内容,如果未能解决你的问题,请参考以下文章

不兼容的 chromedriver 和 chrome 版本,除了它们都是 96

使用 ChromeDriver 和 Chrome DevTools 协议进行多客户端远程调试

会话未创建:此版本的 ChromeDriver 仅支持 Chrome 版本 74 错误与 ChromeDriver Chrome 使用 Selenium

selenium 怎么驱动chromedriver

chrome 和 chromeDriver

chromedriver类怎么引入