55

I installed google-chrome in a Docker, but when I run my Python 2 script of Selenium, it failed like this:

automation@1c17781fef0c:/topology-editor/test$ python test.py
Traceback (most recent call last):
  File "test.py", line 27, in <module>
    browser = webdriver.Chrome()
  File "/usr/local/lib/python2.7/dist-packages/selenium/webdriver/chrome/webdriver.py", line 69, in __init__
    desired_capabilities=desired_capabilities)
  File "/usr/local/lib/python2.7/dist-packages/selenium/webdriver/remote/webdriver.py", line 98, in __init__
    self.start_session(desired_capabilities, browser_profile)
  File "/usr/local/lib/python2.7/dist-packages/selenium/webdriver/remote/webdriver.py", line 185, in start_session
    response = self.execute(Command.NEW_SESSION, parameters)
  File "/usr/local/lib/python2.7/dist-packages/selenium/webdriver/remote/webdriver.py", line 249, in execute
    self.error_handler.check_response(response)
  File "/usr/local/lib/python2.7/dist-packages/selenium/webdriver/remote/errorhandler.py", line 194, in check_response
    raise exception_class(message, screen, stacktrace)
selenium.common.exceptions.WebDriverException: Message: unknown error: Chrome failed to start: crashed
  (Driver info: chromedriver=2.31.488763 (092de99f48a300323ecf8c2a4e2e7cab51de5ba8),platform=Linux 4.4.0-83-generic x86_64)

And if I run google-chrome directly in docker, it shows below:

automation@1c17781fef0c:/topology-editor/test$ google-chrome
Failed to move to new namespace: PID namespaces supported, Network namespace supported, but failed: errno = Operation not permitted
Trace/breakpoint trap (core dumped)
automation@1c17781fef0c:/topology-editor/test$

System:

$ uname -a
Linux 1c17781fef0c 4.4.0-83-generic #106-Ubuntu SMP Mon Jun 26 17:54:43 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux
$ google-chrome --version
Google Chrome 60.0.3112.78
$ chromedriver --version
ChromeDriver 2.31.488763 (092de99f48a300323ecf8c2a4e2e7cab51de5ba8)
Zach
  • 539
  • 1
  • 4
  • 22
J. Fan
  • 731
  • 1
  • 7
  • 9

4 Answers4

88

You need to launch a standalone chrome browser

docker run -d -p 4444:4444 selenium/standalone-chrome

and then in your python script launch browser using Remote webdriver

from selenium import webdriver
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
driver = webdriver.Remote("http://127.0.0.1:4444/wd/hub", DesiredCapabilities.CHROME)

If you want you can also launch a Selenium Grid hub.

To do this as a django test do the following:

# docker-compose.yml

selenium:
  image: selenium/standalone-firefox
  ports:
  - 4444:4444

# project/app/test.py

from django.test import TestCase
from selenium import webdriver
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities


class SiteTest(TestCase):
    fixtures = [
        'app/fixtures/app.json',
        ...
    ]

    def setUp(self):
        self.browser = webdriver.Remote("http://selenium:4444/wd/hub", DesiredCapabilities.FIREFOX)

    def tearDown(self):
        self.browser.quit()

    def test_visit_site(self):
        self.browser.get('http://app:8000/')
        self.assertIn(self.browser.title, 'Home')

Note:

If you use webdriver.ChromeOptions|FirefoxOptions|etc then DesiredCapabalities import is not necessary:

from selenium import webdriver
options = webdriver.ChromeOptions()
options.add_argument('--headless')  # example
driver = webdriver.Remote("http://127.0.0.1:4444/wd/hub", options=options)
oxfn
  • 6,590
  • 2
  • 26
  • 34
Tarun Lalwani
  • 142,312
  • 9
  • 204
  • 265
  • I've tried and run successfully with selenium/standalone-chrome. I failed this because I want to integrate chrome/selenium with another docker images we used before. I'll try the Remote way to run, thanks. – J. Fan Jul 27 '17 at 08:03
  • After a lot of searching in different places I found this to be the answer that worked best for me – Robert Johnstone Mar 16 '20 at 11:30
  • I someone help me to understand why remote link is "http://127.0.0.1" ? – MertTheGreat Aug 11 '20 at 18:58
  • @MertTheGreat, that was updated by someone else but the `127.0.0.1` was just an example. In docker it would be `selenium` – Tarun Lalwani Aug 13 '20 at 05:52
  • It worked for me as I saw that the container that has my app had connected to the selenium container, but the chrome UI did not show up, I did not put it in the headless mode and there was no error, did I miss anything? – Vincent Yuan Jul 03 '21 at 03:38
  • Hi, Do you have a Java example? Thanks – user2451016 Sep 01 '21 at 15:38
  • How do you run the standalone when you want to run this through AWS ECR? e.g i am confused where to put the following docker run -d -p 4444:4444 selenium/standalone-chrome – mgd6 Jan 24 '23 at 15:53
  • @mgd6 you'll add to the `docker-compose.yml`, as shown in the answer – Tiago Martins Peres Jan 24 '23 at 16:09
59

You need to add the next lines to your Dockerfile:

# install google chrome
RUN wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add -
RUN sh -c 'echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google-chrome.list'
RUN apt-get -y update
RUN apt-get install -y google-chrome-stable

# install chromedriver
RUN apt-get install -yqq unzip
RUN wget -O /tmp/chromedriver.zip http://chromedriver.storage.googleapis.com/`curl -sS chromedriver.storage.googleapis.com/LATEST_RELEASE`/chromedriver_linux64.zip
RUN unzip /tmp/chromedriver.zip chromedriver -d /usr/local/bin/

# set display port to avoid crash
ENV DISPLAY=:99

# install selenium
RUN pip install selenium==3.8.0

Then your code should be like this. Especially you need to declare your driver like below:

from selenium import webdriver
chrome_options = webdriver.ChromeOptions()
chrome_options.add_argument('--no-sandbox')
chrome_options.add_argument('--window-size=1920,1080')
chrome_options.add_argument('--headless')
chrome_options.add_argument('--disable-gpu')
driver = webdriver.Chrome(chrome_options=chrome_options)

driver.get('www.google.com')
screenshot = driver.save_screenshot('test.png')
driver.quit()
mirekphd
  • 4,799
  • 3
  • 38
  • 59
Mehmet nuri
  • 840
  • 7
  • 7
  • 2
    Nice work for your configuration with `chrome_options` to start chrome in *headless* mode – J. Fan Mar 22 '19 at 09:59
  • 1
    Thanks for the answer! I'd also mention that the Dockerfile could be improved to follow https://docs.docker.com/develop/develop-images/dockerfile_best-practices/ and produce less layers/less size. For example, all RUN instructions could be combined into one. Also, we don't need to have /tmp/chromedriver.zip file as part of the image and we can remove it after unpacking. Two apt-get install commands can be combined into one. – Slava Semushin Nov 20 '19 at 13:38
  • I like how you downloaded a screenshot, so one can see it's actually working – Sean McCarthy Dec 31 '20 at 19:20
  • It solves quite a few problems but it still doesn't work for me. My script does more than just taking a screenshot and I guess this introduces various new problems. First, there is the tab crash issue, and if you solve that then you have a timeout issue. – Createdd Feb 28 '21 at 11:38
  • 2
    Worth making more explicit as I had issues with this but then resolved... First line of dockerfile should be FROM python:latest – Ryan May 01 '21 at 14:40
  • If you are getting the error: `InvalidArgumentException: Message: invalid argument (Session info: headless chrome=***.*.****.**)` When executing `driver.get('www.google.com')` Try `driver.get('https://www.google.com/')` that worked for me. – Sam Fed Aug 04 '22 at 13:13
14

For people coming through google search, here is the easiest workaround:

Dockerfile

FROM python:3.7

RUN apt-get update 
RUN apt-get install -y gconf-service libasound2 libatk1.0-0 libcairo2 libcups2 libfontconfig1 libgdk-pixbuf2.0-0 libgtk-3-0 libnspr4 libpango-1.0-0 libxss1 fonts-liberation libappindicator1 libnss3 lsb-release xdg-utils

#download and install chrome
RUN wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb
RUN dpkg -i google-chrome-stable_current_amd64.deb; apt-get -fy install

#install python dependencies
COPY requirements.txt requirements.txt 
RUN pip install -r ./requirements.txt 

#some envs
ENV APP_HOME /app 
ENV PORT 5000

#set workspace
WORKDIR ${APP_HOME}

#copy local files
COPY . . 

CMD exec gunicorn --bind :${PORT} --workers 1 --threads 8 main:app 

You will need to install chromedriver_binary pip package which I have added in requirements.txt as:

Flask==1.1.1
gunicorn==20.0.4
selenium==3.141.0
chromedriver-binary==79.0.3945.36

Then your main.py should be like:

from selenium import webdriver
import chromedriver_binary


chrome_options=webdriver.ChromeOptions()
chrome_options.add_argument("--headless")
chrome_options.add_argument("--no-sandbox")
chrome_options.add_argument("window-size=1400,2100") 
chrome_options.add_argument('--disable-gpu')

driver=webdriver.Chrome(chrome_options=chrome_options)

Now, build your Dockerfile using docker build -t <imagename> . and docker run --rm -p <yourPORT>:5000 <imagename>

anisbhsl
  • 149
  • 1
  • 8
  • 2
    FYI you will need to update chromedriver-binary to match the current stable version of chrome or this will error when you try to run "Message: session not created: This version of ChromeDriver only supports Chrome version 79" – Leon Kyriacou Apr 28 '21 at 16:56
  • 1
    Yes @LeonKyriacou I agree. Here is how I automated the version matching between google chrome and the chromedriver : wget -O LATEST_RELEASE http://chromedriver.storage.googleapis.com/LATEST_RELEASE && \ latest=$(cat LATEST_RELEASE) && \ sed -i "s/XXXX/$latest/g" requirements.txt && \ – user1987343 Oct 23 '21 at 06:56
0

I assume you need to run it in headless mode

https://developers.google.com/web/updates/2017/04/headless-chrome

this is how I do it in ruby

capabilities = Selenium::WebDriver::Remote::Capabilities.chrome(
chromeOptions: {args: %w[ no-sandbox headless disable-gpu window-size=1280,1000 ]})

Capybara::Selenium::Driver.new(app, :browser => :chrome, http_client: client, desired_capabilities: capabilities)

You can pretty much adapt your code in python

also consider installing some font libriaries that chrome needs to run on headless

RUN apt-get update && \
    apt-get -qq -y install  libxpm4 libxrender1 libgtk2.0-0 libnss3\ 
       libgconf-2-4  libpango1.0-0 libxss1 libxtst6 fonts-liberation\ 
       libappindicator1 xdg-utils

RUN apt-get -y install \
               xvfb gtk2-engines-pixbuf \
               xfonts-cyrillic xfonts-100dpi xfonts-75dpi xfonts-base xfonts-scalable \
               imagemagick x11-apps zip
skaliber
  • 141
  • 1
  • 4