run selenium with chrome driver on heroku: `cannot find Chrome binary`
Asked Answered
B

4

5

I'm a noob as it comes to linux setup (and heroku), so apologies if this question is basic.

I want to run selenium webkit (in ruby) on Heroku. I face a difficulty that my script cannot find Chrome binary file.

I actually got chrome to work by itself:

~ $ chromedriver
Starting ChromeDriver 2.22.397932 (282ed7cf89cf0053b6542e0d0f039d4123bbb6ad) on port 9515
Only local connections are allowed.

chromedriver being a file that I copied from /app/vendor/bundle/bin/chromedriver, just to make it easier for now. chromedriver file there exists because I installed chromedriver-helper gem. The gem was supposed to make the binary file available for ruby processes but didn't.

I've also tried setting path explicitly, e.g. Selenium::WebDriver::Chrome.driver_path = 'chromedriver' in my ruby code, with the aforementioned file located in the root category.

It all works perfectly locally (with or without the driver_path)

What can be the cause? I've read this SO thread from years ago, but it seems outdated to me. Any ideas would be greatly appreciated!

error trace:

~ $ ruby bin/run.rb
/app/vendor/bundle/ruby/2.2.0/gems/selenium-webdriver-2.53.4/lib/selenium/webdriver/remote/response.rb:70:in `assert_ok': unknown error: cannot find Chrome binary (Selenium::WebDriver::Error::UnknownError)
  (Driver info: chromedriver=2.22.397932 (282ed7cf89cf0053b6542e0d0f039d4123bbb6ad),platform=Linux 3.13.0-91-generic x86_64)
    from /app/vendor/bundle/ruby/2.2.0/gems/selenium-webdriver-2.53.4/lib/selenium/webdriver/remote/response.rb:34:in `initialize'
    from /app/vendor/bundle/ruby/2.2.0/gems/selenium-webdriver-2.53.4/lib/selenium/webdriver/remote/http/common.rb:78:in `new'
    from /app/vendor/bundle/ruby/2.2.0/gems/selenium-webdriver-2.53.4/lib/selenium/webdriver/remote/http/common.rb:78:in `create_response'
    from /app/vendor/bundle/ruby/2.2.0/gems/selenium-webdriver-2.53.4/lib/selenium/webdriver/remote/http/default.rb:90:in `request'
    from /app/vendor/bundle/ruby/2.2.0/gems/selenium-webdriver-2.53.4/lib/selenium/webdriver/remote/http/common.rb:59:in `call'
    from /app/vendor/bundle/ruby/2.2.0/gems/selenium-webdriver-2.53.4/lib/selenium/webdriver/remote/bridge.rb:649:in `raw_execute'
    from /app/vendor/bundle/ruby/2.2.0/gems/selenium-webdriver-2.53.4/lib/selenium/webdriver/remote/bridge.rb:123:in `create_session'
    from /app/vendor/bundle/ruby/2.2.0/gems/selenium-webdriver-2.53.4/lib/selenium/webdriver/remote/bridge.rb:87:in `initialize'
    from /app/vendor/bundle/ruby/2.2.0/gems/selenium-webdriver-2.53.4/lib/selenium/webdriver/chrome/bridge.rb:48:in `initialize'
    from /app/vendor/bundle/ruby/2.2.0/gems/selenium-webdriver-2.53.4/lib/selenium/webdriver/common/driver.rb:64:in `new'
    from /app/vendor/bundle/ruby/2.2.0/gems/selenium-webdriver-2.53.4/lib/selenium/webdriver/common/driver.rb:64:in `for'
    from /app/vendor/bundle/ruby/2.2.0/gems/selenium-webdriver-2.53.4/lib/selenium/webdriver.rb:84:in `for'
    from /app/lib/mealpass_orderer.rb:12:in `initialize'
    from /app/lib/mealpass_orderer.rb:8:in `new'
    from /app/lib/mealpass_orderer.rb:8:in `run'
    from bin/run.rb:3:in `<main>'

UPDATE:

I tried the same with AWS EC2 server (launched instance, cloned git repo, installed all dependencies). The same happens there as well. That is, able to execute chromedriver from terminal, but seeing same error when run the script.

Borderline answered 8/7, 2016 at 4:16 Comment(3)
Have you considered running Poltergeist instead?Domesticity
@IlyaVassilevsky No, I haven't yet tried Poltergeist. I wonder if this error has anything to do with chromedriver having a "head"Borderline
the linked SO question sounds to me like it is exactly the issue you hitPustulate
D
5

ChromeDriver is just a driver for Chrome. It needs the actual Chrome browser installed on the same machine to actually work.

Heroku doesn't have Chrome installed on its dynos by default. You need to use a buildpack that installs Chrome. For example:

https://github.com/dwayhs/heroku-buildpack-chrome

You can see how it fetches Chrome:

https://github.com/dwayhs/heroku-buildpack-chrome/blob/master/bin/compile#L36-38

Domesticity answered 11/7, 2016 at 21:11 Comment(4)
Thanks @Ilya. I tried this buildpack and it didn't work. I'm suspecting installing google chrome (or any browser) on heroku might be more involved.Borderline
Yes, Heroku is a very opinionated and closed platform. It should be much easier to set up Chrome with ChromeDriver on your own VM on AWS, Linode, or DigitalOcean.Domesticity
Thanks for your answer Ilya. I ended up re-writing with Watir with phantomjs because I couldn't get Heroku to install Chrome.Borderline
Your solution does not work for me !!Lapful
B
1

ANSWER

YOUR_PATH = 'whatever/your/path/is' # to your bin dir
CURRENT_DIR = File.expand_path(File.dirname(__FILE__))
CHROMEDRIVER_FN = File.join(CURRENT_DIR, YOUR_PATH, "bin/chromedriver")
# —OR—
#CHROMEDRIVER_FN = File.join(File.absolute_path('..', CURRENT_DIR), YOUR_PATH, "bin/chromedriver")
Selenium::WebDriver::Chrome.driver_path = CHROMEDRIVER_FN

CONTEXT

The example below shows my setup for Selenium Chromedriver in a recent Ruby project.

1) The file structure:

ruby_app/
├── Gemfile
├── Gemfile.lock
├── History.txt
├── Manifest.txt
├── README.md
├── Rakefile
├── bin
│   └── chromedriver
├── doc
├── lib
│   └── ruby_app.rb
└── test
    ├── test_files
    │   ├── test_config.yml
    │   └── uris_array_dump.yml
    ├── test_ruby_app.rb
    ├── test_google.rb
    ├── test_helper.rb
    └── test_output

2) In test/test_helper.rb:

TEST_DIR = File.expand_path(File.dirname(__FILE__))
TEST_FILES = File.join(TEST_DIR, "test_files")
TEST_OUTPUT = File.join(TEST_DIR, "test_output")
CHROMEDRIVER_FN = File.join(File.absolute_path('..', TEST_DIR), "bin", "chromedriver")

The above code uses File.absolute_path, see: http://ruby-doc.org/core-2.3.1/File.html#method-c-absolute_path

Converts a pathname to an absolute pathname. Relative paths are referenced from the current working directory of the process unless dir_string is given, in which case it will be used as the starting point.


3) In test/test_google.rb:

Selenium::WebDriver::Chrome.driver_path = CHROMEDRIVER_FN
Bur answered 8/7, 2016 at 4:54 Comment(6)
Hey man, thanks for your answer. I tried playing with it, including do all of the above in code as well as in the irb console. I also tried hardcoding the executable in bundle folder (/app/vendor/bundle/bin/chromedriver). I tried printing value of CHROMEDRIVER_FN. CHROMEDRIVER_FN gets set correctly. The file is definitely there, but Selenium doesn't see it on runtime.Borderline
I started a bounty for thisBorderline
Too bad. At least we know now that Heroku is the factor here… Good luck with the bounty!Bur
Thanks! Do you know if not running processes on heroku might be the cause? I'm not running server or other processes...Borderline
"third-party buildpacks that enable you to use languages and frameworks beyond those that are officially supported by Heroku." github.com/tstachl/heroku-buildpack-selenium + devcenter.heroku.com/articles/third-party-buildpacksBur
Thanks! I think I've seen one for googlechrome, I'll try to find and use it.Borderline
D
1

Here's a minimal configuration that's worked for me. You'll need to have the right buildpacks to install chrome too, it looks like you're only installing chromedriver which is a separate binary.

https://github.com/jormon/minimal-chrome-on-heroku-xvfb

You can test one-button deploy it to Heroku using the button on the README.md.

Let me know how it goes!

Doriedorin answered 4/7, 2017 at 18:42 Comment(0)
M
0

I know this comes in a bit late. But I had the same issue, and just figured it out. I was going NUTS. Turns out Heroku doesn't really maintain their buildpacks. Therefore, install these buildpacks:

https://github.com/awl19/heroku-buildpack-google-chrome https://github.com/awl19/heroku-buildpack-chromedriver

and of course your heroku/ruby buildpack after those two.

Boom. It'll work like clockwork. Additionally super important, don't forget to explicitly quit the browser after each request, or after a certain amount of time, otherwise it'll be spawned indefinitely, will use up all of your memory, and eventually kill the server. You can do that with

session.quit

I guess for you (wherever you're calling a new capybara session.. maybe inyour controller?) it should look something like this:

session = Capybara::Session.new(:selenium)
   // your browser actions or logic here

 session.quit
Mccorkle answered 28/12, 2023 at 12:0 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.