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.)
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/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"
diff --git a/seleniumbase/core/browser_launcher.py b/seleniumbase/core/browser_launcher.py
index 4243975fb4d..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
@@ -718,7 +719,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 +842,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":
@@ -4239,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,
@@ -4260,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
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)
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"',