2015-12-29 57 views
9

我目前正在玩Selenium Marionette WebDriver。在我的應用程序中,我想依次打開多個Marionette驅動程序。基本上是這樣的:Selenium Marionette驅動程序UnreachableBrowserException在第二次啓動時

MarionetteDriver driver = new MarionetteDriver(); 
// do some stuff 
driver.quit(); 

// a while later 

driver = new MarionetteDriver(); 
// do some stuff 
driver.quit(); 

現在我面臨的問題,只有第一個木偶實例可以成功啓動併爲每個後來的嘗試,我發現了以下情況例外。這個問題每次都會發生,而且使用的端口總是在變化,所以顯然沒有端口衝突。

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 

任何指針讚賞!

回答

8

挖得更深一些後,我來到了以下結論,最終解決了我的問題:

  1. 木偶RESP。 wires使用兩個端口(請參閱wires --help);一個marionette-portwebdriver-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. 當前(版本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); 
+0

我會提出拉請求,我花了差不多2個小時,試圖解決同樣的問題。 – Anton

0

大多數UnreachableBrowserException發生在Selenium找不到驅動程序所需的exe文件時。由於您尚未設置驅動程序功能,因此我認爲以下步驟將解決您的問題。

作爲每Mozilla的MDN link木偶被設置爲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); 

另外,木偶可執行被添加到路徑(在Windows):

添加可執行到PATH

Selenium會嘗試使用路徑中的可執行文件。您需要使用以下內容將其添加到路徑中。

最後,另一個SO question其中處理UnreachableBrowserException問題。

+1

謝謝您的建議。但是,問題不是PATH相關的;正如我所說的,「MarionetteDriver」的第一個實例化工作正常,問題只出現在隨後的嘗試上。我也嘗試使用'RemoteWebDriver',但這也沒有幫助。 – qqilihq

2

您需要處理由木偶所需的二進制文件。您可以手動完成(自行下載二進制文件並導出適當的變量),或者您可以使用​​自動完成。只需添加以下依賴:

<dependency> 
    <groupId>io.github.bonigarcia</groupId> 
    <artifactId>webdrivermanager</artifactId> 
    <version>1.6.0</version> 
</dependency> 

,然後在你的代碼調用:

FirefoxDriverManager.getInstance().setup(); 
+1

雖然這聽起來像是一個非常有用的擴展,但我不確定它是如何解決給定問題的。可能你可以詳細說明嗎? – qqilihq

+0

這個擴展無需在我們的本地機器上配置MarionetteDriver。對我來說它有效。 – SkorpEN

0

我有類似的問題,通過重寫建設者創造執行的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); 
     } 
    } 
} 
相關問題