undetected-chromedriver icon indicating copy to clipboard operation
undetected-chromedriver copied to clipboard

fix executable_path for custom chromedriver

Open smartwifivn opened this issue 3 years ago • 8 comments

browser_executable_path isn't necessary here, because it is defined by binary_location in options argument.

In other hand, chromedriver executable path is missing for patcher. There is no way to set custom chromedriver path. Without executable_path, undetected_chromedriver will alway download chromedriver from its repo and then patch it also.

smartwifivn avatar Jan 04 '22 16:01 smartwifivn

@smartwifivn sometimes this could cause an error like this image It's actually because of the function find_chrome_executable() doesn't return the right path as shown on the screenshot below and then causes the chrome.exe nonfoundable. it is probably because it's on Python 32 bit rather than 64 bit. I will do a double-check with it. image

The temp solution is to send directly the chrome path like this:

exe_path = os.path.normpath("C:\Program Files\Google\Chrome\Application\chrome.exe")
driver = uc.Chrome(browser_executable_path = exe_path)

BenoitYU avatar Jan 05 '22 18:01 BenoitYU

@BenoitYU From v2, browser excutable path can be passed like this:

chrome_exe_path = "your_chrome_path"
options = uc.ChromeOptions()
options.binary_location = chrome_exe_path
driver = uc.Chrome(
    options=options,
)

So the browser_executable_path isn't necessary. Have a look at the current init.py file at line 312-315:

if not options.binary_location:
            options.binary_location = (
                browser_executable_path or find_chrome_executable()
            )

If options.binary_location is set, then browser_executable_path will be meaningless.

smartwifivn avatar Jan 06 '22 02:01 smartwifivn

I vote for this PR too. The executable_path is a must have in my case. Without it the chromedriver is downloaded during each app start which

  1. transfers lot of data
  2. slows down significantly the app startup time (in my case it is really important)
  3. downloads wrong chromedriver version when new chrome is released, which breaks the app without prior warning
  4. it is not a good practice to download part of the application in runtime - I would like to prepare all necessary components during deployment (in my case inside docker container).

So please, put the executable_path back.

Thanks in advance and also big thanks for whole this project!!!

eNcacz avatar Jan 06 '22 07:01 eNcacz

I vote for this PR too. The executable_path is a must have in my case. Without it the chromedriver is downloaded during each app start which

  1. transfers lot of data
  2. slows down significantly the app startup time (in my case it is really important)
  3. downloads wrong chromedriver version when new chrome is released, which breaks the app without prior warning
  4. it is not a good practice to download part of the application in runtime - I would like to prepare all necessary components during deployment (in my case inside docker container).

So please, put the executable_path back.

Thanks in advance and also big thanks for whole this project!!!

One more problem is urlretrieve function doesn't have timeout option, your program should hang forever while downloading chromedriver

smartwifivn avatar Jan 06 '22 15:01 smartwifivn

In support of this change... When running with multiprocessing each process downloads chromedriver, which is not only highly inefficient, but also results in this error: OSError: [Errno 26] Text file busy: '/root/.local/share/undetected_chromedriver/chromedriver' Can this be merged soon, or shall we be patching on our own?

dnissimi avatar Feb 01 '22 16:02 dnissimi

Would love to get some traction on this PR, or just any way to avoid redownloading chromedriver.

navels avatar Feb 07 '22 18:02 navels

I think this is a good idea and proposed the very same approach in #496, with the added capability of specifying that the binary be patched and used from a mkdtemp directory.

essandess avatar Feb 23 '22 16:02 essandess

it would be great if this project integrated features from this module ( https://pypi.org/project/chromedriver-autoinstaller/ ).this would make it easier since now the module just blindly downloads the latest version but if it had features like the chromedriver-autoinstaller it would be able to download the driver according to the currently installed version of chrome rather than the latest

mjishnu avatar Jul 11 '22 16:07 mjishnu

If you dont want to redownload every time, use

Chrome(driver_executable_path="your/driver/path/chromedriver")

and if you want specific version @eNcacz

Chrome(version_main=101)

ultrafunkamsterdam avatar Oct 15 '22 18:10 ultrafunkamsterdam

If you dont want to redownload every time, use

Chrome(driver_executable_path="your/driver/path/chromedriver")

and if you want specific version @eNcacz

Chrome(version_main=101)

It doesn't look like the "driver_executable_path" solution works for me, on Linux.

mdonova33 avatar Nov 22 '22 00:11 mdonova33

I had the same experience on ubuntu: I did specify the executable_path but only specifying the version helped (once you are using the last minor of the specified major). Thanks for the suggestions.

rbecerril avatar Nov 22 '22 02:11 rbecerril

@rbecerril could you show a snippet? I have the following line: uc.Chrome(options=chrome_options,version_main=101, driver_executable_path="/home/mike/.local/share/undetected_chromedriver/chromedriver", use_subprocess=True)

And it's still downloading the driver every single time. Am I missing something? @ultrafunkamsterdam

mdonova33 avatar Nov 22 '22 14:11 mdonova33

sure, I use a patch:

        """ a patch to chromedriver is needed to be able to set the path of the executable """
        def force_patcher_to_use(directory):
            executable_path = os.path.join(directory, "chromedriver")

            """ monkey patch the Patcher class """
            class PatcherWithForcedExecutablePath(uc_patcher):
                def __init__(self, *args, **kwargs):
                    kwargs["executable_path"] = executable_path
                    super().__init__(*args, **kwargs)
        
            uc.Patcher = PatcherWithForcedExecutablePath
        
            return executable_path

        uc.Chrome.__init__(self, options=options,
                           executable_path=force_patcher_to_use(self.user_data_path),
                           version_main=chromium_version)
                           

I am using chromium_version = 99, so I do not think it updates

rbecerril avatar Nov 23 '22 01:11 rbecerril

sure, I use a patch:

        """ a patch to chromedriver is needed to be able to set the path of the executable """
        def force_patcher_to_use(directory):
            executable_path = os.path.join(directory, "chromedriver")

            """ monkey patch the Patcher class """
            class PatcherWithForcedExecutablePath(uc_patcher):
                def __init__(self, *args, **kwargs):
                    kwargs["executable_path"] = executable_path
                    super().__init__(*args, **kwargs)
        
            uc.Patcher = PatcherWithForcedExecutablePath
        
            return executable_path

        uc.Chrome.__init__(self, options=options,
                           executable_path=force_patcher_to_use(self.user_data_path),
                           version_main=chromium_version)

I am using chromium_version = 99, so I do not think it updates

Would this code go in the patcher.py file, and then I would reinstall the package? Sorry for my ignorance on this, this will be a huge help.

EDIT: After looking more into it, it looks like I just add that def to my code, and change my uc.Chrome lines to include that function. However, it gives me a problem with the "uc_patcher" variable, saying that it's not defined. Do I have to do something with that?

EDIT2: Glad everyone can see me learning on the fly here, ha. Changing "uc_patcher" to "uc.Patcher" works, now I just have a permissions issue to fix, its resulting in the following error: "PermissionError: [Errno 13] Permission denied: '/usr/bin/chromedriver'"

EDIT3: The conclusion to the trilogy...by creating a copy of the webdriver executable and moving it to a directory in my local user folder, it looks like the permission issue gets solved and everything runs.

mdonova33 avatar Nov 27 '22 17:11 mdonova33