Драйвер Selenium Marionette UnreachableBrowserException при втором запуске
В настоящее время я играю с Selenium Marionette WebDriver
, В моем приложении я хочу открыть несколько драйверов Marionette последовательно. В основном как то так:
MarionetteDriver driver = new MarionetteDriver();
// do some stuff
driver.quit();
// a while later
driver = new MarionetteDriver();
// do some stuff
driver.quit();
Теперь я сталкиваюсь с проблемой, что только первый экземпляр Marionette может быть успешно запущен, и для каждой последующей попытки я получаю следующее исключение. Проблема возникает каждый раз, и используемый порт всегда меняется, поэтому, очевидно, нет конфликта портов.
Exception in thread "main" org.openqa.selenium.remote.UnreachableBrowserException: Could not start a new session. Possible causes are invalid address of the remote server or browser start-up failure.
Build info: version: '2.48.2', revision: '41bccdd10cf2c0560f637404c2d96164b67d9d67', time: '2015-10-09 13:08:06'
System info: host: 'qqilihq.local', ip: '192.168.1.2', os.name: 'Mac OS X', os.arch: 'x86_64', os.version: '10.11.2', java.version: '1.7.0_71'
Driver info: driver.version: MarionetteDriver
at org.openqa.selenium.remote.RemoteWebDriver.execute(RemoteWebDriver.java:641)
at org.openqa.selenium.remote.RemoteWebDriver.startSession(RemoteWebDriver.java:247)
at org.openqa.selenium.remote.RemoteWebDriver.startSession(RemoteWebDriver.java:232)
at org.openqa.selenium.firefox.MarionetteDriver.run(MarionetteDriver.java:84)
at org.openqa.selenium.firefox.MarionetteDriver.<init>(MarionetteDriver.java:73)
at org.openqa.selenium.firefox.MarionetteDriver.<init>(MarionetteDriver.java:45)
at MyMainClass.main(MyMainClass.java:131)
Caused by: org.openqa.selenium.WebDriverException: org.apache.http.conn.HttpHostConnectException: Connect to localhost:41886 [localhost/127.0.0.1, localhost/0:0:0:0:0:0:0:1] failed: Connection refused
Build info: version: '2.48.2', revision: '41bccdd10cf2c0560f637404c2d96164b67d9d67', time: '2015-10-09 13:08:06'
System info: host: 'qqilihq.local', ip: '192.168.1.2', os.name: 'Mac OS X', os.arch: 'x86_64', os.version: '10.11.2', java.version: '1.7.0_71'
Driver info: driver.version: MarionetteDriver
at org.openqa.selenium.remote.service.DriverCommandExecutor.execute(DriverCommandExecutor.java:91)
at org.openqa.selenium.remote.RemoteWebDriver.execute(RemoteWebDriver.java:620)
... 6 more
Caused by: org.apache.http.conn.HttpHostConnectException: Connect to localhost:41886 [localhost/127.0.0.1, localhost/0:0:0:0:0:0:0:1] failed: Connection refused
at org.apache.http.impl.conn.DefaultHttpClientConnectionOperator.connect(DefaultHttpClientConnectionOperator.java:151)
at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.connect(PoolingHttpClientConnectionManager.java:353)
at org.apache.http.impl.execchain.MainClientExec.establishRoute(MainClientExec.java:380)
at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:236)
at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:184)
at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:88)
at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:110)
at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:184)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:71)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:55)
at org.openqa.selenium.remote.internal.ApacheHttpClient.fallBackExecute(ApacheHttpClient.java:143)
at org.openqa.selenium.remote.internal.ApacheHttpClient.execute(ApacheHttpClient.java:89)
at org.openqa.selenium.remote.HttpCommandExecutor.execute(HttpCommandExecutor.java:142)
at org.openqa.selenium.remote.service.DriverCommandExecutor.execute(DriverCommandExecutor.java:82)
... 7 more
Caused by: java.net.ConnectException: Connection refused
at java.net.PlainSocketImpl.socketConnect(Native Method)
at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:339)
at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:200)
at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:182)
at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)
at java.net.Socket.connect(Socket.java:579)
at org.apache.http.conn.socket.PlainConnectionSocketFactory.connectSocket(PlainConnectionSocketFactory.java:74)
at org.apache.http.impl.conn.DefaultHttpClientConnectionOperator.connect(DefaultHttpClientConnectionOperator. java:134)
... 20 more
Любые указатели приветствуются!
4 ответа
Покопавшись немного глубже, я пришел к следующим выводам, которые в конечном итоге решили мою проблему:
Марионетка соотв.
wires
использует два порта (см.wires --help
);marionette-port
иwebdriver-port
:Usage: ./wires [OPTIONS] WebDriver to marionette proxy. optional arguments: -h,--help show this help message and exit -b,--binary BINARY Path to the Firefox binary --webdriver-host WEBDRIVER_HOST Host to run webdriver server on --webdriver-port WEBDRIVER_PORT Port to run webdriver on --marionette-port MARIONETTE_PORT Port to run marionette on --connect-existing Connect to an existing firefox process
При запуске нескольких
MarionetteDrivers
одновременно оба порта должны явно отличаться от уже запущенного экземпляра. Однако при использовании конструктора по умолчаниюnew MarionetteDriver()
marionette-port
остается постоянным (и не определяется на основе свободного порта). Мы использовали некоторые обходные пути (см. Ниже) дляGeckoDriverService.Builder
всегда выбирать два случайно выбранных доступных порта.Текущая (версия 2.48.2)
GeckoDriverService
имеет пустую реализациюwaitUntilAvailable()
(который должен проверить, еслиWebDriver
готов к работе). Спорадически это приводит кUnreachableBrowserException
размещено выше.
Чтобы обойти эти проблемы, мы сделали что-то вроде этого в конце:
// determine free ports for Marionette and WebDriver
final int marionettePort = PortProber.findFreePort();
final int webDriverPort = PortProber.findFreePort();
// override, as GeckoDriverService provides no direct way to set the Marionette port
GeckoDriverService.Builder builder = new GeckoDriverService.Builder() {
@Override
protected ImmutableList<String> createArgs() {
Builder<String> argsBuilder = ImmutableList.builder();
argsBuilder.addAll(super.createArgs());
argsBuilder.add(String.format("--marionette-port=%d", marionettePort));
return argsBuilder.build();
}
};
builder.usingPort(webDriverPort);
builder.usingDriverExecutable(pathToDriver);
GeckoDriverService driverService = builder.build();
try {
driverService.start();
} catch (IOException e) {
throw new IllegalStateException("Could not start the GeckoDriverService", e);
}
try {
// keep checking the WebDriver port via Socket until it's available;
// as far as I could tell, there is nothing more "high level", e.g. REST API
waitUntilReady(webDriverPort, TimeUnit.SECONDS.toMillis(30));
} catch (InterruptedException e) {
// ignore
}
return new MarionetteDriver(driverService, capabilities);
Вы должны обработать двоичный файл, требуемый Марионеткой. Вы можете сделать это вручную (загрузить двоичный файл самостоятельно и экспортировать соответствующую переменную), или вы можете сделать это автоматически с помощью WebDriverManager. Просто добавьте следующую зависимость:
<dependency>
<groupId>io.github.bonigarcia</groupId>
<artifactId>webdrivermanager</artifactId>
<version>1.6.0</version>
</dependency>
И тогда в вашем коде вызовите:
FirefoxDriverManager.getInstance().setup();
В основном UnreachableBrowserException
происходит, когда Selenium не может найти требуемый exe драйвера. Поскольку вы не установили возможности драйвера, я предполагаю, что следующие шаги решат вашу проблему.
Согласно ссылке Mozilla MDN Marionette устанавливается как DesiredCapability
DesiredCapabilities capabilities = DesiredCapabilities.firefox();
// Set Marionette on so the Grid will use this instead of normal FirefoxDriver
capabilities.setCapability("marionette", true);
WebDriver driver = new RemoteWebDriver(capabilities);
Также к пути добавляется исполняемый файл Marionette (в Windows):
Добавление исполняемого файла в PATH
Selenium попытается использовать исполняемый файл в пути. Вам нужно будет добавить его к пути, используя следующее.
Наконец, еще один вопрос SO, где обрабатывается проблема UnreachableBrowserException.
У меня была похожая проблема, решенная путем создания переопределенного экземпляра MarionetteDriver с переопределенной реализацией компоновщика. Принятый ответ - более элегантное решение. Было много времени, чтобы глубоко в корне
public static class CustomBuilder extends org.openqa.selenium.firefox.GeckoDriverService.Builder {
@Override
protected GeckoDriverService createDriverService(File exe, int port, ImmutableList<String> args, ImmutableMap<String, String> environment) {
try {
return new GeckoDriverService(exe, port, args, environment) {
@Override
protected void waitUntilAvailable() throws MalformedURLException {
logger.info("Waiting until avaliable");
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
}
super.waitUntilAvailable();
logger.info("Finished waiting until avaliable");
}
};
} catch (IOException e) {
throw new WebDriverException(e);
}
}
}