From a14b74f2b7c35728f7637526551943705b537e0c Mon Sep 17 00:00:00 2001 From: Michael Mintz Date: Tue, 13 Aug 2024 00:14:29 -0400 Subject: [PATCH 1/6] Improve `uc_gui_click_x_y()` --- seleniumbase/core/browser_launcher.py | 40 ++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/seleniumbase/core/browser_launcher.py b/seleniumbase/core/browser_launcher.py index 4243975fb4d..7ae3686d2f3 100644 --- a/seleniumbase/core/browser_launcher.py +++ b/seleniumbase/core/browser_launcher.py @@ -718,7 +718,44 @@ def _uc_gui_click_x_y(driver, x, y, timeframe=0.25, uc_lock=False): def uc_gui_click_x_y(driver, x, y, timeframe=0.25): - _uc_gui_click_x_y(driver, x, y, timeframe=timeframe, uc_lock=True) + gui_lock = fasteners.InterProcessLock( + constants.MultiBrowser.PYAUTOGUILOCK + ) + with gui_lock: # Prevent issues with multiple processes + install_pyautogui_if_missing(driver) + import pyautogui + pyautogui = get_configured_pyautogui(pyautogui) + if IS_WINDOWS: + width_ratio = 1.0 + window_rect = driver.get_window_rect() + width = window_rect["width"] + height = window_rect["height"] + win_x = window_rect["x"] + win_y = window_rect["y"] + if ( + hasattr(sb_config, "_saved_width_ratio") + and sb_config._saved_width_ratio + ): + width_ratio = sb_config._saved_width_ratio + else: + scr_width = pyautogui.size().width + driver.maximize_window() + win_width = driver.get_window_size()["width"] + width_ratio = round(float(scr_width) / float(win_width), 2) + width_ratio += 0.01 + if width_ratio < 0.45 or width_ratio > 2.55: + width_ratio = 1.01 + sb_config._saved_width_ratio = width_ratio + driver.minimize_window() + driver.set_window_rect(win_x, win_y, width, height) + x = x * width_ratio + y = y * width_ratio + _uc_gui_click_x_y(driver, x, y, timeframe=timeframe, uc_lock=False) + return + page_actions.switch_to_window( + driver, driver.current_window_handle, 2, uc_lock=False + ) + _uc_gui_click_x_y(driver, x, y, timeframe=timeframe, uc_lock=False) def _on_a_cf_turnstile_page(driver): @@ -804,6 +841,7 @@ def _uc_gui_click_captcha( width_ratio = round(float(scr_width) / float(win_width), 2) + 0.01 if width_ratio < 0.45 or width_ratio > 2.55: width_ratio = 1.01 + sb_config._saved_width_ratio = width_ratio driver.minimize_window() driver.set_window_rect(win_x, win_y, width, height) if ctype == "cf_t": From 5c8a94b856c8ac17610997221f05213c82e10f84 Mon Sep 17 00:00:00 2001 From: Michael Mintz Date: Tue, 13 Aug 2024 00:15:36 -0400 Subject: [PATCH 2/6] Improve UC Mode reliability --- seleniumbase/core/browser_launcher.py | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/seleniumbase/core/browser_launcher.py b/seleniumbase/core/browser_launcher.py index 7ae3686d2f3..54fbdd7555a 100644 --- a/seleniumbase/core/browser_launcher.py +++ b/seleniumbase/core/browser_launcher.py @@ -12,6 +12,7 @@ from selenium import webdriver from selenium.common.exceptions import ElementClickInterceptedException from selenium.common.exceptions import InvalidSessionIdException +from selenium.common.exceptions import SessionNotCreatedException from selenium.webdriver.chrome.service import Service as ChromeService from selenium.webdriver.common.options import ArgOptions from selenium.webdriver.common.service import utils as service_utils @@ -4277,11 +4278,11 @@ def get_local_driver( driver.quit() except Exception: pass + uc_path = None + if os.path.exists(LOCAL_UC_DRIVER): + uc_path = LOCAL_UC_DRIVER + uc_path = os.path.realpath(uc_path) try: - uc_path = None - if os.path.exists(LOCAL_UC_DRIVER): - uc_path = LOCAL_UC_DRIVER - uc_path = os.path.realpath(uc_path) driver = undetected.Chrome( options=chrome_options, user_data_dir=user_data_dir, @@ -4298,6 +4299,19 @@ def get_local_driver( mac_certificate_error = True else: raise + except SessionNotCreatedException: + time.sleep(0.2) + driver = undetected.Chrome( + options=chrome_options, + user_data_dir=user_data_dir, + driver_executable_path=uc_path, + browser_executable_path=b_path, + enable_cdp_events=cdp_events, + headless=False, # Xvfb needed! + version_main=uc_chrome_version, + use_subprocess=True, # Always! + ) + uc_activated = True if mac_certificate_error: cf_lock_path = ( constants.MultiBrowser.CERT_FIXING_LOCK From 6af03b6ebde226780dc2ea46739cd85f004d8b61 Mon Sep 17 00:00:00 2001 From: Michael Mintz Date: Tue, 13 Aug 2024 00:17:25 -0400 Subject: [PATCH 3/6] Improve command-line control for SB() and Driver() formats --- seleniumbase/plugins/driver_manager.py | 85 ++++++++++++++++++-------- seleniumbase/plugins/sb_manager.py | 85 ++++++++++++++++++-------- 2 files changed, 116 insertions(+), 54 deletions(-) diff --git a/seleniumbase/plugins/driver_manager.py b/seleniumbase/plugins/driver_manager.py index 9ee7f4529aa..6c292433e5e 100644 --- a/seleniumbase/plugins/driver_manager.py +++ b/seleniumbase/plugins/driver_manager.py @@ -303,28 +303,44 @@ def Driver( proxy_string = proxy_string[1:-1] c_a = chromium_arg if c_a is None and "--chromium-arg" in arg_join: - if "--chromium-arg=" in arg_join: - c_a = arg_join.split("--chromium-arg=")[1].split(" ")[0] - elif "--chromium-arg " in arg_join: - c_a = arg_join.split("--chromium-arg ")[1].split(" ")[0] - if c_a: - if c_a.startswith('"') and c_a.endswith('"'): - c_a = c_a[1:-1] - elif c_a.startswith("'") and c_a.endswith("'"): - c_a = c_a[1:-1] + count = 0 + for arg in sys_argv: + if arg.startswith("--chromium-arg="): + c_a = arg.split("--chromium-arg=")[1] + break + elif arg == "--chromium-arg" and len(sys_argv) > count + 1: + c_a = sys_argv[count + 1] + if c_a.startswith("-"): + c_a = None + break + count += 1 chromium_arg = c_a d_f = disable_features if d_f is None and "--disable-features" in arg_join: - if "--disable-features=" in arg_join: - d_f = arg_join.split("--disable-features=")[1].split(" ")[0] - elif "--disable-features " in arg_join: - d_f = arg_join.split("--disable-features ")[1].split(" ")[0] - if d_f: - if d_f.startswith('"') and d_f.endswith('"'): - d_f = d_f[1:-1] - elif c_a.startswith("'") and d_f.endswith("'"): - d_f = d_f[1:-1] + count = 0 + for arg in sys_argv: + if arg.startswith("--disable-features="): + d_f = arg.split("--disable-features=")[1] + break + elif arg == "--disable-features" and len(sys_argv) > count + 1: + d_f = sys_argv[count + 1] + if d_f.startswith("-"): + d_f = None + break + count += 1 disable_features = d_f + if agent is None and "--agent" in arg_join: + count = 0 + for arg in sys_argv: + if arg.startswith("--agent="): + agent = arg.split("--agent=")[1] + break + elif arg == "--agent" and len(sys_argv) > count + 1: + agent = sys_argv[count + 1] + if agent.startswith("-"): + agent = None + break + count += 1 user_agent = agent recorder_mode = False if recorder_ext: @@ -535,15 +551,30 @@ def Driver( host_resolver_rules = ( arg_join.split("--host_resolver_rules=")[1].split('"')[0] ) - if driver_version is None: - if "--driver-version=" in arg_join: - driver_version = ( - arg_join.split("--driver-version=")[1].split(" ")[0] - ) - elif "--driver_version=" in arg_join: - driver_version = ( - arg_join.split("--driver_version=")[1].split(" ")[0] - ) + if driver_version is None and "--driver-version" in arg_join: + count = 0 + for arg in sys_argv: + if arg.startswith("--driver-version="): + driver_version = arg.split("--driver-version=")[1] + break + elif arg == "--driver-version" and len(sys_argv) > count + 1: + driver_version = sys_argv[count + 1] + if driver_version.startswith("-"): + driver_version = None + break + count += 1 + if driver_version is None and "--driver_version" in arg_join: + count = 0 + for arg in sys_argv: + if arg.startswith("--driver_version="): + driver_version = arg.split("--driver_version=")[1] + break + elif arg == "--driver_version" and len(sys_argv) > count + 1: + driver_version = sys_argv[count + 1] + if driver_version.startswith("-"): + driver_version = None + break + count += 1 browser_name = browser # Launch a web browser diff --git a/seleniumbase/plugins/sb_manager.py b/seleniumbase/plugins/sb_manager.py index 938b0f3fd0a..787430e11a3 100644 --- a/seleniumbase/plugins/sb_manager.py +++ b/seleniumbase/plugins/sb_manager.py @@ -337,28 +337,44 @@ def SB( proxy_string = proxy_string[1:-1] c_a = chromium_arg if c_a is None and "--chromium-arg" in arg_join: - if "--chromium-arg=" in arg_join: - c_a = arg_join.split("--chromium-arg=")[1].split(" ")[0] - elif "--chromium-arg " in arg_join: - c_a = arg_join.split("--chromium-arg ")[1].split(" ")[0] - if c_a: - if c_a.startswith('"') and c_a.endswith('"'): - c_a = c_a[1:-1] - elif c_a.startswith("'") and c_a.endswith("'"): - c_a = c_a[1:-1] + count = 0 + for arg in sys_argv: + if arg.startswith("--chromium-arg="): + c_a = arg.split("--chromium-arg=")[1] + break + elif arg == "--chromium-arg" and len(sys_argv) > count + 1: + c_a = sys_argv[count + 1] + if c_a.startswith("-"): + c_a = None + break + count += 1 chromium_arg = c_a d_f = disable_features if d_f is None and "--disable-features" in arg_join: - if "--disable-features=" in arg_join: - d_f = arg_join.split("--disable-features=")[1].split(" ")[0] - elif "--disable-features " in arg_join: - d_f = arg_join.split("--disable-features ")[1].split(" ")[0] - if d_f: - if d_f.startswith('"') and d_f.endswith('"'): - d_f = d_f[1:-1] - elif c_a.startswith("'") and d_f.endswith("'"): - d_f = d_f[1:-1] + count = 0 + for arg in sys_argv: + if arg.startswith("--disable-features="): + d_f = arg.split("--disable-features=")[1] + break + elif arg == "--disable-features" and len(sys_argv) > count + 1: + d_f = sys_argv[count + 1] + if d_f.startswith("-"): + d_f = None + break + count += 1 disable_features = d_f + if agent is None and "--agent" in arg_join: + count = 0 + for arg in sys_argv: + if arg.startswith("--agent="): + agent = arg.split("--agent=")[1] + break + elif arg == "--agent" and len(sys_argv) > count + 1: + agent = sys_argv[count + 1] + if agent.startswith("-"): + agent = None + break + count += 1 user_agent = agent recorder_mode = False if recorder_ext: @@ -679,15 +695,30 @@ def SB( host_resolver_rules = ( arg_join.split("--host_resolver_rules=")[1].split('"')[0] ) - if driver_version is None: - if "--driver-version=" in arg_join: - driver_version = ( - arg_join.split("--driver-version=")[1].split(" ")[0] - ) - elif "--driver_version=" in arg_join: - driver_version = ( - arg_join.split("--driver_version=")[1].split(" ")[0] - ) + if driver_version is None and "--driver-version" in arg_join: + count = 0 + for arg in sys_argv: + if arg.startswith("--driver-version="): + driver_version = arg.split("--driver-version=")[1] + break + elif arg == "--driver-version" and len(sys_argv) > count + 1: + driver_version = sys_argv[count + 1] + if driver_version.startswith("-"): + driver_version = None + break + count += 1 + if driver_version is None and "--driver_version" in arg_join: + count = 0 + for arg in sys_argv: + if arg.startswith("--driver_version="): + driver_version = arg.split("--driver_version=")[1] + break + elif arg == "--driver_version" and len(sys_argv) > count + 1: + driver_version = sys_argv[count + 1] + if driver_version.startswith("-"): + driver_version = None + break + count += 1 if highlights is not None: try: highlights = int(highlights) From 9aa60a3cb523b0147ffa32a4d726928f712b1553 Mon Sep 17 00:00:00 2001 From: Michael Mintz Date: Tue, 13 Aug 2024 00:19:28 -0400 Subject: [PATCH 4/6] Refresh Python dependencies --- mkdocs_build/requirements.txt | 6 +++--- requirements.txt | 4 ++-- setup.py | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/mkdocs_build/requirements.txt b/mkdocs_build/requirements.txt index 0dda4afae78..3252765b9b5 100644 --- a/mkdocs_build/requirements.txt +++ b/mkdocs_build/requirements.txt @@ -11,12 +11,12 @@ MarkupSafe==2.1.5 Jinja2==3.1.4 click==8.1.7 ghp-import==2.1.0 -watchdog==4.0.1 +watchdog==4.0.2 cairocffi==1.7.1 pathspec==0.12.1 -Babel==2.15.0 +Babel==2.16.0 paginate==0.5.6 -lxml==5.2.2 +lxml==5.3.0 pyquery==2.0.0 readtime==3.0.0 mkdocs==1.6.0 diff --git a/requirements.txt b/requirements.txt index fb2aba19f13..a1db416a6b5 100755 --- a/requirements.txt +++ b/requirements.txt @@ -31,7 +31,7 @@ sniffio==1.3.1 h11==0.14.0 outcome==1.3.0.post0 trio==0.22.2;python_version<"3.8" -trio==0.26.1;python_version>="3.8" +trio==0.26.2;python_version>="3.8" trio-websocket==0.11.1 wsproto==1.2.0 websocket-client==1.8.0;python_version>="3.8" @@ -66,7 +66,7 @@ pygments==2.17.2;python_version<"3.8" pygments==2.18.0;python_version>="3.8" pyreadline3==3.4.1;platform_system=="Windows" tabcompleter==1.3.3 -pdbp==1.5.3 +pdbp==1.5.4 colorama==0.4.6 pyotp==2.9.0 python-xlib==0.33;platform_system=="Linux" diff --git a/setup.py b/setup.py index 548c1533397..b44033ebaea 100755 --- a/setup.py +++ b/setup.py @@ -179,7 +179,7 @@ 'h11==0.14.0', 'outcome==1.3.0.post0', 'trio==0.22.2;python_version<"3.8"', - 'trio==0.26.1;python_version>="3.8"', + 'trio==0.26.2;python_version>="3.8"', 'trio-websocket==0.11.1', 'wsproto==1.2.0', 'websocket-client==1.8.0;python_version>="3.8"', @@ -214,7 +214,7 @@ 'pygments==2.18.0;python_version>="3.8"', 'pyreadline3==3.4.1;platform_system=="Windows"', "tabcompleter==1.3.3", - "pdbp==1.5.3", + "pdbp==1.5.4", 'colorama==0.4.6', 'pyotp==2.9.0', 'python-xlib==0.33;platform_system=="Linux"', From 567dd9b2634436062716c5a5232dcccd18216722 Mon Sep 17 00:00:00 2001 From: Michael Mintz Date: Tue, 13 Aug 2024 00:19:51 -0400 Subject: [PATCH 5/6] Update the docs --- README.md | 2 +- help_docs/method_summary.md | 2 -- help_docs/uc_mode.md | 2 -- 3 files changed, 1 insertion(+), 5 deletions(-) diff --git a/README.md b/README.md index 56f2a8a5abb..22a3e83273d 100755 --- a/README.md +++ b/README.md @@ -58,7 +58,7 @@ 📚 Learn from [**over 200 examples** in the **SeleniumBase/examples/** folder](https://github.com/seleniumbase/SeleniumBase/tree/master/examples). -👤 Note that SeleniumBase UC Mode / Stealth Mode has its own ReadMe. +👤 Note that SeleniumBase UC Mode (Stealth Mode) has its own ReadMe. â„šī¸ Scripts can be called via python, although some Syntax Formats expect pytest (a Python unit-testing framework included with SeleniumBase that can discover & collect tests automatically). diff --git a/help_docs/method_summary.md b/help_docs/method_summary.md index be5be59cec7..b99dea1e743 100644 --- a/help_docs/method_summary.md +++ b/help_docs/method_summary.md @@ -1083,8 +1083,6 @@ driver.uc_gui_click_captcha(frame="iframe", retry=False, blind=False) driver.uc_gui_handle_captcha(frame="iframe") # (Auto-detects the CAPTCHA) # driver.uc_gui_handle_cf(frame="iframe") # PyAutoGUI click CF Turnstile # driver.uc_gui_handle_rc(frame="iframe") # PyAutoGUI click G. reCAPTCHA - -driver.uc_switch_to_frame(frame="iframe") # Stealthy switch_to_frame() ``` -------- diff --git a/help_docs/uc_mode.md b/help_docs/uc_mode.md index 02a3cee806b..797388e760a 100644 --- a/help_docs/uc_mode.md +++ b/help_docs/uc_mode.md @@ -199,8 +199,6 @@ driver.uc_gui_click_captcha(frame="iframe", retry=False, blind=False) driver.uc_gui_handle_captcha(frame="iframe") # driver.uc_gui_handle_cf(frame="iframe") # driver.uc_gui_handle_rc(frame="iframe") - -driver.uc_switch_to_frame(frame, reconnect_time=None) ``` (Note that the reconnect_time is used to specify how long the driver should be disconnected from Chrome to prevent detection before reconnecting again.) From fde610fa92803d71fe059811e1ea36c46ae842a9 Mon Sep 17 00:00:00 2001 From: Michael Mintz Date: Tue, 13 Aug 2024 00:20:36 -0400 Subject: [PATCH 6/6] Version 4.29.9 --- seleniumbase/__version__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/seleniumbase/__version__.py b/seleniumbase/__version__.py index d2d7216f068..ed3ba16611b 100755 --- a/seleniumbase/__version__.py +++ b/seleniumbase/__version__.py @@ -1,2 +1,2 @@ # seleniumbase package -__version__ = "4.29.8" +__version__ = "4.29.9"