@@ -109,7 +109,18 @@ def _download_chromedriver(
109109 path_to_cached_chrome_driver : str ,
110110 ) -> str :
111111 url = "https://googlechromelabs.github.io/chrome-for-testing/known-good-versions-with-downloads.json"
112- response = ChromeDriverManager .send_http_get_request (url ).json ()
112+ response = ChromeDriverManager .send_http_get_request (url )
113+ if response is None :
114+ raise RuntimeError (
115+ "Could not download known-good-versions-with-downloads.json"
116+ )
117+
118+ response = response .json ()
119+ if response is None :
120+ raise RuntimeError (
121+ "Could not parse known-good-versions-with-downloads.json"
122+ )
123+ assert isinstance (response , dict )
113124
114125 matching_versions = [
115126 item
@@ -118,7 +129,7 @@ def _download_chromedriver(
118129 ]
119130
120131 if not matching_versions :
121- raise Exception (
132+ raise RuntimeError (
122133 f"No compatible ChromeDriver found for Chrome version { chrome_major_version } "
123134 )
124135
@@ -142,6 +153,11 @@ def _download_chromedriver(
142153 )
143154 response = ChromeDriverManager .send_http_get_request (driver_url )
144155
156+ if response is None :
157+ raise Exception (
158+ f"Could not download ChromeDriver from { driver_url } "
159+ )
160+
145161 Path (path_to_driver_cache_dir ).mkdir (parents = True , exist_ok = True )
146162 zip_path = os .path .join (path_to_driver_cache_dir , "chromedriver.zip" )
147163 print ( # noqa: T201
@@ -179,6 +195,9 @@ def send_http_get_request(url: str) -> Response:
179195 f"html2print: "
180196 f"failed to get response for URL: { url } with error: { last_error } "
181197 )
198+ raise RuntimeError (
199+ f"GET request failed after 3 attempts: { url } "
200+ ) from last_error
182201
183202 @staticmethod
184203 def get_chrome_version () -> Optional [str ]:
@@ -328,14 +347,23 @@ def create_webdriver(
328347 service = Service (path_to_chrome )
329348
330349 webdriver_options = Options ()
350+ # Workaround for Windows: chrome is not typically found in the PATH, so need to supply the exact binary location manually
351+ if platform .system () == "Windows" :
352+ import browsers
353+
354+ webdriver_options .binary_location = browsers .get ("chrome" )["path" ]
331355 webdriver_options .add_argument ("start-maximized" )
332356 webdriver_options .add_argument ("disable-infobars" )
333357 # Doesn't seem to be needed.
334358 # webdriver_options.add_argument('--disable-gpu') # noqa: ERA001
335359 webdriver_options .add_argument ("--disable-extensions" )
336- webdriver_options .add_argument ("--headless=chrome" )
337- # FIXME: This is not nice but otherwise it does not work in Ubuntu 24-based Docker image.
338- # https://github.com/SeleniumHQ/selenium/issues/15327#issuecomment-2689287561
360+ # Use --headless=new, as it seems to be more stable on Windows (available since Chrome 109).
361+ # see https://www.selenium.dev/blog/2023/headless-is-going-away/
362+ webdriver_options .add_argument ("--headless=new" )
363+ # Docker disables some syscalls that are required for Chrome's sandbox to work.
364+ # https://stackoverflow.com/questions/68855734/how-to-setup-chrome-sandbox-on-docker-container.
365+ # See also https://github.com/SeleniumHQ/selenium/issues/15327#issuecomment-2689287561.
366+ # We prefer isolation of the container over isolation of tabs within Chrome, and thus disable the sandbox.
339367 webdriver_options .add_argument ("--no-sandbox" )
340368
341369 # The Chrome option --disable-dev-shm-usage disables the use of /dev/shm
0 commit comments