joyzoursky / docker-python-chromedriver

Dockerfile for running Python Selenium in headless Chrome (Python 2.7 / 3.6 / 3.7 / 3.8 / Alpine based Python / Chromedriver / Selenium / Xvfb included in different versions)
https://hub.docker.com/r/joyzoursky/python-chromedriver/
MIT License
636 stars 196 forks source link

Error: 'chromedriver' executable needs to be in PATH. #14

Open as3379 opened 4 years ago

as3379 commented 4 years ago

I have implemented your dockfile into my project which uses webdriver chrome to run the python test script (using mac OS) . However when tried, it errors out as follows:

image

Docker file:

Use an official Python runtime as a parent image

FROM python:3.7 ENV APP_DIR /app WORKDIR $APP_DIR

ENV PYTHONPATH="$PYTHONPATH:/app"

COPY uits uits COPY requirements.txt requirements.txt COPY setup.py setup.py

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

upgrade pip

RUN pip install --upgrade pip

install required additional dependencies

RUN pip install -r requirements.txt

Test script look like this:

class SeleniumClient(object): """ A wrapper for selenium's client with various handy extensions. """ def init(self, params=None, config="default", driver=None): if driver is not None: self.driver = driver return

    if params['location'] != "local":
        return

    root = os.path.dirname(os.path.realpath(__file__))
    self.logger.info("%s" , _platform)
    if _platform == "darwin":
        user = getpass.getuser()
        download_folder = "/Users/%s/downloads/" % user
    elif "win32" in _platform:
        user = getpass.getuser()
        download_folder = "/Users/%s/downloads/" % user
    elif "linux" in _platform:
        download_folder = "/var/lib/docker"
    else:
        raise NotImplemented("don't know where to save data")
    if "chrome" in config:
        options = webdriver.ChromeOptions()
        preferences = {
            "profile.default_content_settings.popups": 0,
            "download.default_directory": download_folder,
            "credentials_enable_service": 0,
            "profile.password_manager_enabled": 0
        }
        options.add_experimental_option("prefs", preferences)
        if config == "chrome":
            options.add_argument("--start-fullscreen")
        elif config == "chrome_headless":
            options.add_argument('--headless')
            options.add_argument('--disable-gpu')
            options.add_argument("--window-size=1920, 1200")
        self.driver = webdriver.Chrome(executable_path='usr/bin/local',options=options)
joyzoursky commented 4 years ago

There are 2 problems in this script:

  1. The executable path is not correct, it should be /usr/local/bin/chromedriver (but it is actually not required as it should be the default location)
  2. For headless Chrome, --no-sandbox argument is also needed, otherwise it may crash when running

For me I would change the last part of the script like this:

if config == "chrome":
    options.add_argument("--start-fullscreen")
elif config == "chrome_headless":
    options.add_argument('--no-sandbox')
    options.add_argument('--headless')
    options.add_argument('--disable-gpu')
    options.add_argument("--window-size=1920, 1200")
self.driver = webdriver.Chrome(options=options)

Or it should also works with the correct executable path: (make sure it starts with /)

if config == "chrome":
    options.add_argument("--start-fullscreen")
elif config == "chrome_headless":
    options.add_argument('--no-sandbox')
    options.add_argument('--headless')
    options.add_argument('--disable-gpu')
    options.add_argument("--window-size=1920, 1200")
self.driver = webdriver.Chrome(executable_path='/usr/local/bin/chromedriver', options=options)
stevenhurwitt commented 3 years ago

did you resolve this issue?

tried using this in my Dockerfile and even added to path (which may be wrong?) with

RUN export PATH=$PATH:/usr/local/bin/chromedriver

this is the code i'm using:

opts = Options()
    opts.add_argument('--no-sandbox')
    opts.add_argument('--ignore-certificate-errors')
    opts.add_argument('--start-maximized')
    opts.add_argument('--disable-dev-shm-usage')
    #opts.binary_location = '/usr/bin/google-chrome-stable'

    with open(creds, 'r') as f:
        creds = json.load(f)

    if headless:
        opts.add_argument('--headless')
        assert opts.headless

        def enable_download_headless(browser, download_dir):
            browser.command_executor._commands["send_command"] = ("POST", '/session/$sessionId/chromium/send_command')
            params = {'cmd':'Page.setDownloadBehavior', 'params': {'behavior': 'allow', 'downloadPath': download_dir}}
            browser.execute("send_command", params)

        prefs = {
            'download.default_directory': download_path,
            'download.prompt_for_download': False,
            'download.directory_upgrade': True,
            'safebrowsing.enabled': False,
            'safebrowsing.disable_download_protection': True}

    else:
        prefs = {
            'download.prompt_for_download': False,
            'safebrowsing.enabled': False,
            'safebrowsing.disable_download_protection': True}

    opts.add_experimental_option("prefs", prefs)

    browser = Chrome(executable_path = '/usr/local/bin/chromedriver', options = opts)
joyzoursky commented 3 years ago

@stevenhurwitt Could you try with adding these arguments, see if the crash still happens?

opts.add_argument('--no-sandbox')
opts.add_argument('--headless')
opts.add_argument('--disable-gpu')
stevenhurwitt commented 3 years ago

yeah so i think the issue was that it needed to be in the same directory as the script and i needed some additional dependencies for the ubuntu docker container. reference here