带Selenium的Chromedriver远程调试端口

时间:2018-02-27 18:06:35

标签: ruby selenium selenium-chromedriver google-chrome-headless

我正在使用Capybara Selenium运行无头Chrome,效果很好,除了我无法弄清楚如何使用远程调试。当我添加--remote-debugging-port=4444--remote-debugging-port=9222--remote-debugging-port=9521时,Selenium不再连接到浏览器来运行测试。

如何让远程调试工作?这是我的参考代码:

Capybara.register_driver :selenium do |app|
  # from https://github.com/SeleniumHQ/selenium/issues/3738
  capabilities = Selenium::WebDriver::Remote::Capabilities.chrome(loggingPrefs: {browser: 'ALL'})
  options = Selenium::WebDriver::Chrome::Options.new
  options.add_argument '--disable-infobars' # hide info bar about chrome automating test
  # if we don't use this flag, every selenium test will die with the error:
  # "unknown error: Chrome failed to start: exited abnormally"
  options.add_argument '--no-sandbox'
  # BREAKS THINGS if uncommented
  # options.add_argument '--remote-debugging-port=4444'
  options.add_argument '--headless'
  options.add_argument '--window-size=1600,2400'
  options.add_preference('profile.default_content_settings.popups', 0)
  options.add_preference('download.default_directory', DownloadHelpers::PATH.to_s)
  Capybara::Selenium::Driver.new(
    app,
    clear_local_storage: true,
    clear_session_storage: true,
    browser: :chrome,
    options: options,
    desired_capabilities: capabilities,
  )
end

3 个答案:

答案 0 :(得分:4)

chrome 67 and chromedriver 2.39起,chromedriver现在正确使用您使用--remote-debugging-port指定的端口。这消除了相当多的复杂性from my answer above。我现在采取的步骤(适用于需要使用chrome_remote配置下载设置的用例)如下:

它使用了nodejs库crmux - 它允许多个客户端同时连接到chrome的远程调试端口。

  1. 首先安装nodejs:Nodejs v9.7.0正常工作
  2. 运行npm install crmux -g
  3. 安装crmux
  4. 之前启动chromedriver(Capybara::Selenium::Driver.new),您需要spawn一个单独的线程,它将启动crmux你和chromedriver通过在Capybara(4444)指定的的端口与chrome本身进行通信:

    crmux --port=4444 --listen=4444

  5. 您可能希望在主脚本/线程中的sleep 3命令之后添加spawn,以便在继续测试启动之前为crmux提供时间。

  6. 然后,您可以使用chrome_remote(例如)使用端口 4444 访问chrome,而capybara正在执行此操作。

答案 1 :(得分:0)

更新:如果使用Chrome 67 / chromedriver 2.39之后的版本,my alternative answer above provides a simpler solution

此处的核心问题是Chromedriver还使用远程调试端口连接与Chrome进行通信。这使用websocket协议,它只支持一次连接的单个客户端。通常,当chromedriver启动chromedriver进程时,它将选择一个随机的免费TCP端口号并使用它来访问远程调试端口。但是,如果您指定--remote-debuggging-port=9222,则会使用您请求的调试端口打开Chrome,但是chromedriver会默默地继续尝试使用此随机端口号打开连接。

我最终得到的解决方案受comment 20 in this chromedriver issue的启发。它需要相当多的代码才能使它工作,但是能够稳定地运行。它使用了nodejs库crmux - 它允许多个客户端同时连接到chrome的远程调试端口。

  1. 首先安装nodejs:Nodejs v9.7.0正常工作
  2. 运行npm install crmux -g
  3. 安装crmux
  4. 之前你启动chromedriver(Capybara::Selenium::Driver.new),你需要spawn一个单独的线程,它会做一些事情:寻找chromedriver尝试的远程调试端口用于连接到chrome,然后使用它来启动crmux。一旦发生这种情况,Capybara等将正常工作。
  5. 我的单独线程运行ruby脚本,该脚本首先重复执行netstat命令,直到找到chromedriver的相关条目(TCP状态为SYN_SENT)。 当Chrome启动并运行时,此单独的线程必须继续在后台运行
  6. 这个代码是:

    $chrdrv_wait_timeout = 60
    $chrdrv_exe = "chromedriver.exe"
    
    def get_netstat_output
      stdout = `netstat -a -b -n`
      stat_lines = stdout.split("\n")
      stat_lines
    end
    
    def try_get_requested_port
      socket_state = "SYN_SENT" # i.e. sent with no reply
      statout = get_netstat_output
      n = statout.length
      i = 0
      loop do
        i += 1
        # find lines relating to chromedriver
        exe_match = /^ +\[#{$chrdrv_exe}\]$/.match statout[i]
        if exe_match != nil
          # check preceeding lines which should contain port info
          port_match = /TCP.*:([0-9]+)\W+#{socket_state}/.match statout[i-1]
          if port_match != nil
            return port_match[1].to_i
          end
        end
        break unless i < n
      end
      return nil
    end
    
    def get_tcp_port_requested_by_chromedriver
      i = 1
      loop do
        puts "Waiting for #{$chrdrv_exe}: #{i}"
        port = try_get_requested_port
        if port != nil
          return port
        end
        break unless i < $chrdrv_wait_timeout
        sleep 1
        i += 1
      end
      raise Exception, "Failed to get TCP port requested by #{$chrdrv_exe} (gave up after #{$chrdrv_wait_timeout} seconds)"
    end
    

    (我在Windows中工作:对于Mac / Linux,netstat语法/输出可能不同,因此代码需要调整;关键是你需要它来输出可执行文件所有者每个连接条目的> - 并解析与chromedriver相关的位以获得有问题的端口。

    1. 一旦找到随机端口(我将 12225 作为示例),后台ruby脚本就可以执行crmux进程,该进程将使用chrome重新组合chromedriver本身通过Capybara(4444)中指定的端口

      crmux --port=4444 --listen=12225

    2. 最后,这个单独的脚本将发现的侦听端口保存到文本文件中。这允许运行capybara的主脚本/线程通过从该文件读入端口来知道它可以用来访问chrome(通过crmux的多路复用连接)的端口号。因此,您可以使用chrome_remote来使用端口 12225 来访问chrome,例如,虽然Capybara正在做其事情。

答案 2 :(得分:0)

更新我的ChromeDriver为我修复了它。我没有做任何其他事情。在尝试开始测试之前它会挂起。

具体来说,我使用ChromeDriver 2.36并升级到ChromeDriver 2.40。我不认为Chrome版本是个问题,因为我之前和之后都在Chrome 67上。

以下是我注册驱动程序的方法:

Capybara.register_driver :headless_chrome do |app|
  capabilities = Selenium::WebDriver::Remote::Capabilities.chrome(
    chromeOptions: { args: %w[headless window-size=1280,960 remote-debugging-port=9222] }
  )
  Capybara::Selenium::Driver.new(app, browser: :chrome, desired_capabilities: capabilities)
end

之后我运行了我的测试,调试器(binding.pry)放置在我想要检查的位置。然后当我点击调试器时,我在Chrome的正常实例中导航到http://localhost:9222/,并且能够按照链接查看无头Chrome实例中发生的情况,包括我需要的浏览器控制台输出。