【问题标题】:Chromedriver remote-debugging-port with Selenium带有 Selenium 的 Chromedriver 远程调试端口
【发布时间】:2018-02-27 18:06:34
【问题描述】:

我正在使用 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

【问题讨论】:

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


    【解决方案1】:

    更新我的 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 实例中发生的情况,包括我需要的浏览器控制台输出。

    【讨论】:

      【解决方案2】:

      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 安装 crmux
      3. 启动 chromedriver (Capybara::Selenium::Driver.new) 之前,您需要 spawn 一个单独的线程,该线程将启动 crmux,这将让您和 chromedriver 通过Capybara (4444) 中指定的端口

        crmux --port=4444 --listen=4444

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

      然后你可以使用chrome_remote(例如)通过端口4444访问chrome,而capybara正在做它的事情。

      【讨论】:

      • --port--listen 设置为同一个端口时似乎不起作用。那是错字吗? (如果crmux 已经在监听端口,chrome 给出 `bind() 返回错误,errno=98: Address already in use`。)你是如何让它工作的?我还不清楚哪些东西指向哪些端口。你能用示例源代码编辑你的答案吗?
      • 糟糕,部分问题是我使用的是 chromedriver 2.37,而不是 2.39+。升级到 2.45 解决了我的第一个问题(Selenium::WebDriver::Chrome 在尝试握手时挂起)。现在要弄清楚端口...
      • 我终于想通了:您可以使用browser_options.args << "--remote-debugging-port=9222" 将Chrome --remote-debugging-port 设置为您想要的任何内容(默认为0,这使得它选择随机端口)。 (无论是否使用 crmux,都可以这样设置端口。)然后您设置 crmux 以侦听 不同 端口,例如 9223(默认),但您必须通过 --port 9222 same 端口与 Chrome 的“--remote-debugging-port”,因为它是代理流量的端口。现在您可以从chrome_remote、其他浏览器等连接到 crmux 的 listen 端口。
      • 如果您有兴趣,我编写了一个 gem 来帮助将 crmux 和 chrome_remote 与 Capybara 集成,类似于您的做法:github.com/TylerRick/capybara-chrome_dev_tools。如果您有任何建议或改进,请告诉我或贡献。我还添加了github.com/TylerRick/capybara-chrome_response_headers,它使用chrome_remote 在您的测试中为您提供response_headersstatus_code
      • @TylerRick - --port--listen 被有意设置为同一个端口。 我完全同意这不应该工作 - 但在我的情况下它确实如此。正如您在启动 chrome 本身时所描述的那样,我还在设置 --remote-debugging-port 。我在 Windows 环境中工作...顺便说一句,在 gem 上做得很好。
      【解决方案3】:

      更新:如果使用 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 安装 crmux
      3. 你启动 chromedriver (Capybara::Selenium::Driver.new) 之前,你需要 spawn 一个单独的线程来做一些事情:寻找远程调试端口 chromedriver 试图用来连接到 chrome,和然后用它来启动crmux。一旦发生这种情况,Capybara 等将正常工作。
      4. 我的单独线程运行一个 ruby​​ 脚本,该脚本首先重复执行 netstat 命令,直到找到 chromedriver 的相关条目(TCP 状态为 SYN_SENT)。 当 chrome 启动并运行时,这个单独的线程必须继续在后台运行

      代码如下:

      $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 进程,该进程将通过端口将 chromedriver 与 chrome 本身重新结合 你在Capybara(4444)中指定:

        crmux --port=4444 --listen=12225

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

      【讨论】:

        猜你喜欢
        • 2015-03-12
        • 2021-07-16
        • 2012-04-22
        • 1970-01-01
        • 1970-01-01
        • 2020-08-03
        • 1970-01-01
        • 2011-01-25
        • 1970-01-01
        相关资源
        最近更新 更多