如何使用 Rails 应用程序在 Heroku 上正确 运行 Selenium Webdriver

How to run Selenium Webdriver correctly on Heroku with a Rails app

我正在使用 watir gem 在我的应用程序上实现一个非常基本的 scraper。它 运行 在本地非常好,但是当我在 heroku 上 运行 它时,它会触发此错误:Webdrivers::BrowserNotFound: Failed to find Chrome binary.

我在我的应用程序中添加了 google-chrome 和 chrome 驱动程序构建包,以告诉 Selenium 在 Heroku 上哪里可以找到 Chrome,但它仍然不起作用。此外,当我打印选项时,二进制文件似乎已正确设置:

#<Selenium::WebDriver::Chrome::Options:0x0000558bdf7ecc30 @args=#<Set: {"--user-data-dir=/app/tmp/chrome", "--no-sandbox", "--window-size=1200x600", "--headless", "--disable-gpu"}>, @binary="/app/.apt/usr/bin/google-chrome-stable", @prefs={}, @extensions=[], @options={}, @emulation={}, @encoded_extensions=[]>

这是我的应用程序 Buildpack 网址:

1. heroku/ruby
2. heroku/google-chrome
3. heroku/chromedriver

这是我的代码:

def new_browser(downloads: false)

  options = Selenium::WebDriver::Chrome::Options.new

  chrome_dir = File.join Dir.pwd, %w(tmp chrome)
  FileUtils.mkdir_p chrome_dir
  user_data_dir = "--user-data-dir=#{chrome_dir}"
  options.add_argument user_data_dir

  if chrome_bin = ENV["GOOGLE_CHROME_SHIM"]
    options.add_argument "--no-sandbox"
    options.binary = chrome_bin
  end

  options.add_argument "--window-size=1200x600"
  options.add_argument "--headless"
  options.add_argument "--disable-gpu"

  browser = Watir::Browser.new :chrome, options: options

  if downloads
    downloads_dir = File.join Dir.pwd, %w(tmp downloads)
    FileUtils.mkdir_p downloads_dir

    bridge = browser.driver.send :bridge
    path = "/session/#{bridge.session_id}/chromium/send_command"
    params = { behavior: "allow", downloadPath: downloads_dir }
    bridge.http.call(:post, path, cmd: "Page.setDownloadBehavior",
                                  params: params)
  end
  browser
end

知道如何解决这个问题吗?我在不同的网站上检查了很多类似的问题,但我没有找到任何东西。

我最近两天也在做同样的事情,正如你所说,我尝试了很多不同的事情。我终于成功了。

问题是 heroku 使用不同的路径下载 chrome 驱动程序。在 webdriver gem 的源代码中,我发现 webdriver 正在寻找 (linux, mac os, windows) 的默认系统路径,这就是为什么起作用的原因本地或 WD_CHROME_PATH 环境变量中定义的路径。要在 heroku 上设置路径,我们必须设置这个环境变量

"WD_CHROME_PATH": "/app/.apt/usr/bin/google-chrome"

必须 google-chrome 而不是 google-chrome-稳定,就像我们在示例中找到的那样。

也就是说,只是 运行 来自终端的这个:

heroku config:set WD_CHROME_PATH=/app/.apt/usr/bin/google-chrome

没有适合我的解决方案(Heroku-18 堆栈,使用 'https://github.com/heroku/heroku-buildpack-google-chrome.git' 和 'https://github.com/heroku/heroku-buildpack-chromedriver' 构建包)。

我尝试了各种解决方案,但终于找到了一种可以自己调试的防故障方法。

它涉及到一些资源: https://www.simon-neutert.de/2018/watir-chrome-heroku/https://github.com/jormon/minimal-chrome-on-heroku/blob/master/runner.thor 特别是。

检查您的实际二进制文件和驱动程序在 Heroku 上的位置:

$ heroku run bash
~ $ which chromedriver
/app/.chromedriver/bin/chromedriver
~ $ which google-chrome
/app/.apt/usr/bin/google-chrome

buildpacks 为我设置的 shim 不起作用。事实上,即使你在 Heroku 上将上面的值设置为不同的值,buildpacks 会重置它们,所以你会丢失新的垫片(参见此处:https://github.com/heroku/heroku-buildpack-google-chrome/blob/master/bin/compile)所以我制作了新的垫片:

$ heroku config:set GOOGLE_CHROME_REAL=/app/.apt/usr/bin/google-chrome
$ heroku config:set CHROME_DRIVER_REAL=/app/.chromedriver/bin/chromedriver

然后,我修改了浏览器初始化程序(来自:https://github.com/jormon/minimal-chrome-on-heroku/blob/master/runner.thor):

def new_browser(downloads: false)
    require 'watir'
    require 'webdrivers'
    options = Selenium::WebDriver::Chrome::Options.new

    # make a directory for chrome if it doesn't already exist
    chrome_dir = File.join Dir.pwd, %w(tmp chrome)
    FileUtils.mkdir_p chrome_dir
    user_data_dir = "--user-data-dir=#{chrome_dir}"
    # add the option for user-data-dir
    options.add_argument user_data_dir

    # let Selenium know where to look for chrome if we have a hint from
    # heroku. chromedriver-helper & chrome seem to work out of the box on osx,
    # but not on heroku.
    if chrome_bin = ENV["GOOGLE_CHROME_REAL"]
        Selenium::WebDriver::Chrome.path = chrome_bin
    end
    if chrome_driver = ENV["CHROME_DRIVER_REAL"]
        Selenium::WebDriver::Chrome.driver_path = chrome_driver
    end

    # headless!
    options.add_argument "--window-size=1200x600"
    options.add_argument "--headless"
    options.add_argument "--disable-gpu"

    # make the browser
    browser = Watir::Browser.new :chrome, options: options

    # setup downloading options
    if downloads
      # make download storage directory
      downloads_dir = File.join Dir.pwd, %w(tmp downloads)
      FileUtils.mkdir_p downloads_dir

      # tell the bridge to use downloads
      bridge = browser.driver.send :bridge
      path = "/session/#{bridge.session_id}/chromium/send_command"
      params = { behavior: "allow", downloadPath: downloads_dir }
      bridge.http.call(:post, path, cmd: "Page.setDownloadBehavior",
                                    params: params)
    end
    browser
end

希望这对其他人有帮助。

我曾尝试用不同的方法解决此问题一段时间,但 none 的方法奏效了。然后我检查了 webdrivers 源代码,发现你需要设置“WD_CHROME_PATH”环境变量才能工作。只需在此处附上我的完整设置。这花了我几个小时来调试和修复。

spec_helper.rb

require 'webdrivers'
require 'capybara/rspec'

 # Heroku build packs need to put the chromedriver binary in a non-standard location specified by GOOGLE_CHROME_SHIM
 chrome_bin = ENV.fetch('GOOGLE_CHROME_SHIM', nil)

 options = {}
 options[:args] = ['headless', 'disable-gpu', 'window-size=1280,1024']
 options[:binary] = chrome_bin if chrome_bin

 Capybara.register_driver :headless_chrome do |app|
   Capybara::Selenium::Driver.new(app,
      browser: :chrome,
      options: Selenium::WebDriver::Chrome::Options.new(options)
    )
 end

 Capybara.javascript_driver = :headless_chrome

宝石文件

group :test do
  gem 'capybara'
  gem 'timecop'
  gem 'selenium-webdriver'
  gem 'webdrivers'
end

app.json

{
  "name": "evocal",
  "repository": "https://github.com/zeitdev/evocal",
  "environments": {
    "test": {
      "addons":[
        "heroku-postgresql:in-dyno"
      ],
      "scripts": {
        "test-setup": "bundle exec rake db:seed",
        "test": "bundle exec rspec"
      },
      "buildpacks": [
        { "url": "heroku/ruby" },
        { "url": "https://github.com/heroku/heroku-buildpack-google-chrome" },
        { "url": "https://github.com/heroku/heroku-buildpack-chromedriver" },
        { "url": "heroku/nodejs" }
      ],
      "env": {
        "WD_CHROME_PATH": "/app/.apt/opt/google/chrome/chrome"
      }
    }
  }
}

我还不完全理解 selenium、webdriver 和 gem 是如何相互作用的。一些人还写道,您可以留下另一个构建包。但这至少现在有效:-D.