2017-01-02 11 views
9

埋め込みSelenium/PhantomJSDriverドライバでは、リソースがクリーンアップされていないようです。クライアントを同期して実行すると、何百万ものファイルがオープンし、最終的には「ファイルが多すぎます」という例外が発生します。ここで 開いているファイルが多すぎます(Selenium + PhantomJSDriver)

は、プログラムが〜1分 lsof-pフラグを使用すると、小さい結果セットを持っている理由を、私は理解していない

$ lsof | awk '{ print $2; }' | uniq -c | sort -rn | head 
    1221966 12180 
     34790 29773 
     31260 12138 
     20955 8414 
     17940 10343 
     16665 32332 
     9512 27713 
     7275 19226 
     5496 7153 
     5040 14065 

$ lsof -p 12180 | awk '{ print $2; }' | uniq -c | sort -rn | head 
    2859 12180 
     1 PID 

$ lsof -p 12180 -Fn | sort -rn | uniq -c | sort -rn | head 
    1124 npipe 
    536 nanon_inode 
     4 nsocket 
     3 n/opt/jdk/jdk1.8.0_60/jre/lib/jce.jar 
     3 n/opt/jdk/jdk1.8.0_60/jre/lib/charsets.jar 
     3 n/dev/urandom 
     3 n/dev/random 
     3 n/dev/pts/20 
     2 n/usr/share/sbt-launcher-packaging/bin/sbt-launch.jar 
     2 n/usr/share/java/jayatana.jar 

のために実行されている間、私はlsofから集められたいくつかの出力です。しかし、ほとんどのエントリはpipeanon_inodeです。

クライアントは~100行で非常にシンプルで、使用終了時にdriver.close()driver.quit()を呼び出します。私はキャッシュとクライアントを再利用して実験したが、私はバグ修正があった場合にはセレンの複数のバージョンを試してみました

case class HeadlessClient(
          country: String, 
          userAgent: String, 
          inheritSessionId: Option[Int] = None 
         ) { 
    protected var numberOfRequests: Int = 0 
    protected val proxySessionId: Int = inheritSessionId.getOrElse(new Random().nextInt(Integer.MAX_VALUE)) 
    protected val address = InetAddress.getByName("proxy.domain.com") 
    protected val host = address.getHostAddress 
    protected val login: String = HeadlessClient.username + proxySessionId 
    protected val windowSize = new org.openqa.selenium.Dimension(375, 667) 

    protected val (mobProxy, seleniumProxy) = { 

    val proxy = new BrowserMobProxyServer() 
    proxy.setTrustAllServers(true) 
    proxy.setChainedProxy(new InetSocketAddress(host, HeadlessClient.port)) 
    proxy.chainedProxyAuthorization(login, HeadlessClient.password, AuthType.BASIC) 
    proxy.addLastHttpFilterFactory(new HttpFiltersSourceAdapter() { 
     override def filterRequest(originalRequest: HttpRequest): HttpFilters = { 
     new HttpFiltersAdapter(originalRequest) { 
      override def proxyToServerRequest(httpObject: HttpObject): io.netty.handler.codec.http.HttpResponse = { 
      httpObject match { 
       case req: HttpRequest => req.headers().remove(HttpHeaders.Names.VIA) 
       case _ => 
      } 
      null 
      } 
     } 
     } 
    }) 
    proxy.enableHarCaptureTypes(CaptureType.REQUEST_CONTENT, CaptureType.RESPONSE_CONTENT) 
    proxy.start(0) 
    val seleniumProxy = ClientUtil.createSeleniumProxy(proxy) 
    (proxy, seleniumProxy) 
    } 

    protected val driver: PhantomJSDriver = { 
    val capabilities: DesiredCapabilities = DesiredCapabilities.chrome() 
    val cliArgsCap = new util.ArrayList[String] 
    cliArgsCap.add("--webdriver-loglevel=NONE") 
    cliArgsCap.add("--ignore-ssl-errors=yes") 
    cliArgsCap.add("--load-images=no") 

    capabilities.setCapability(CapabilityType.PROXY, seleniumProxy) 
    capabilities.setCapability("phantomjs.page.customHeaders.Referer", "") 
    capabilities.setCapability("phantomjs.page.settings.userAgent", userAgent) 
    capabilities.setCapability(PhantomJSDriverService.PHANTOMJS_CLI_ARGS, cliArgsCap) 

    new PhantomJSDriver(capabilities) 
    } 

    driver.executePhantomJS(
    """ 
     |var navigation = []; 
     | 
     |this.onNavigationRequested = function(url, type, willNavigate, main) { 
     | navigation.push(url) 
     | console.log('Trying to navigate to: ' + url); 
     |} 
     | 
     |this.onResourceRequested = function(request, net) { 
     | console.log("Requesting " + request.url); 
     | if (! (navigation.indexOf(request.url) > -1)) { 
     |  console.log("Aborting " + request.url) 
     |  net.abort(); 
     | } 
     |}; 
    """.stripMargin 
) 

    driver.manage().window().setSize(windowSize) 

    def follow(url: String)(implicit ec: ExecutionContext): List[HarEntry] = { 
    try{ 
     Await.result(Future{ 
     mobProxy.newHar(url) 
     driver.get(url) 
     val entries = mobProxy.getHar.getLog.getEntries.asScala.toList 
     shutdown() 
     entries 
     }, 45.seconds) 
    } catch { 
     case e: Exception => 
     try { 
      shutdown() 
     } catch { 
      case shutdown: Exception => 
      throw new Exception(s"Error ${shutdown.getMessage} cleaning up after Exception: ${e.getMessage}") 
     } 

     throw e 
    } 
    } 

    def shutdown() = { 
    driver.close() 
    driver.quit() 
    } 
} 

それが開いているファイルを軽減しませんでした。 build.sbt:

libraryDependencies += "org.seleniumhq.selenium" % "selenium-java" % "3.0.1" 
libraryDependencies += "net.lightbody.bmp" % "browsermob-core" % "2.1.2"   

はまた、私はPhantomJS 2.0.1を試みたが、2.1.1:

$ phantomjs --version 
    2.0.1-development 

$ phantomjs --version 
    2.1.1 

これはPhantomJSまたはセレンの問題ですか?クライアントがAPIを不適切に使用していますか?

+0

正当な回答がなかったため、私は賞金を受け取っていません。 Boniは速いアイデアを提供しましたが、コメントに返信したり、さらに対話しませんでした。それは公正ですか? – nkconnor

答えて

3

リソース使用率はBrowserMobによって発生します。プロキシを閉じてそのリソースをクリーンアップするには、stop()に電話する必要があります。 shutdown方法

def shutdown() = { 
    mobProxy.stop() 
    driver.close() 
    driver.quit() 
} 

に別の方法、abortを修正すること、このクライアントの

は、プロキシサーバの即時停止を提供し、中止するトラフィックを待ちません。

0

私の意見では、PhantomJSの問題と思われます。

  1. 使用phantomjs 2.5.0-beta:あなたは、次の選択肢を試すことができます。最近リリースされました。このアップグレードで問題が解決するかどうかはわかりませんが、少なくとも試してみる価値はあります。変更履歴によると、このバージョンの新機能は次のとおりです。

    • アップグレードQtWebKit QtWebKitNG
    • アップグレードのQt 5.7.1
  2. にクリーンphantomjsプロセスwebdriverをを閉じた後。独自のクリーナーを実装して、driver.close()killall -9 phantomjsなどを呼び出した後)が実際に閉じられるように強制することができます。

+0

PhantomJSプロセスを破棄しても、開いているファイルはまだ存在します – nkconnor

関連する問題