UC Mode
breakpoint is active, you can't use Selenium
commands in the browser, and the browser can't detect Selenium
.)
-π€ On Linux, you may need to use `driver.uc_gui_handle_cf()` to successfully bypass a Cloudflare CAPTCHA. If there's more than one iframe on that website (and Cloudflare isn't the first one) then put the CSS Selector of that iframe as the first arg to `driver.uc_gui_handle_cf()`. This method uses `pyautogui`. In order for `pyautogui` to focus on the correct element, use `xvfb=True` / `--xvfb` to activate a special virtual display on Linux.
+π€ On Linux, you may need to use `driver.uc_gui_click_cf()` to successfully bypass a Cloudflare CAPTCHA. If there's more than one iframe on that website (and Cloudflare isn't the first one) then put the CSS Selector of that iframe as the first arg to `driver.uc_gui_click_cf()`. This method uses `pyautogui`. In order for `pyautogui` to focus on the correct element, use `xvfb=True` / `--xvfb` to activate a special virtual display on Linux.
+
+π€ `driver.uc_gui_click_cf(frame="iframe", retry=False, blind=False)` has three args. (All optional). The first one, `frame`, lets you specify the iframe in case the CAPTCHA is not located in the first iframe on the page. The second one, `retry`, lets you retry the click after reloading the page if the first one didn't work (and a CAPTCHA is still present after the page reload). The third arg, `blind`, will retry after a page reload (if the first click failed) by clicking at the last known coordinates of the CAPTCHA checkbox without confirming first with Selenium that a CAPTCHA is still on the page.
π€ To find out if UC Mode will work at all on a specific site (before adjusting for timing), load your site with the following script:
diff --git a/mkdocs_build/requirements.txt b/mkdocs_build/requirements.txt
index 73f59a3b895..eaf0295a961 100644
--- a/mkdocs_build/requirements.txt
+++ b/mkdocs_build/requirements.txt
@@ -20,7 +20,7 @@ lxml==5.2.2
pyquery==2.0.0
readtime==3.0.0
mkdocs==1.6.0
-mkdocs-material==9.5.27
+mkdocs-material==9.5.28
mkdocs-exclude-search==0.6.6
mkdocs-simple-hooks==0.1.5
mkdocs-material-extensions==1.3.1
diff --git a/requirements.txt b/requirements.txt
index 9cddf0cc5c3..f9e49ca33ff 100755
--- a/requirements.txt
+++ b/requirements.txt
@@ -3,11 +3,11 @@ pip>=24.1.1;python_version>="3.8"
packaging>=24.0;python_version<"3.8" packaging>=24.1;python_version>="3.8"
setuptools>=68.0.0;python_version<"3.8" -setuptools>=70.1.1;python_version>="3.8"
+setuptools>=70.2.0;python_version>="3.8"
wheel>=0.42.0;python_version<"3.8" wheel>=0.43.0;python_version>="3.8"
attrs>=23.2.0
-certifi>=2024εΉ΄6ζ2ζ₯
+certifi>=2024εΉ΄7ζ4ζ₯
exceptiongroup>=1.2.1
filelock>=3.12.2;python_version<"3.8" filelock>=3.15.4;python_version>="3.8"
@@ -29,7 +29,7 @@ sniffio==1.3.1
h11==0.14.0
outcome==1.3.0.post0
trio==0.22.2;python_version<"3.8" -trio==0.25.1;python_version>="3.8"
+trio==0.26.0;python_version>="3.8"
trio-websocket==0.11.1
wsproto==1.2.0
websocket-client==1.8.0;python_version>="3.8"
diff --git a/seleniumbase/__version__.py b/seleniumbase/__version__.py
index 4b67644ca06..e965f8ed76b 100755
--- a/seleniumbase/__version__.py
+++ b/seleniumbase/__version__.py
@@ -1,2 +1,2 @@
# seleniumbase package
-__version__ = "4.28.3"
+__version__ = "4.28.4"
diff --git a/seleniumbase/core/browser_launcher.py b/seleniumbase/core/browser_launcher.py
index 79afe2ce8b1..687e5f0ece5 100644
--- a/seleniumbase/core/browser_launcher.py
+++ b/seleniumbase/core/browser_launcher.py
@@ -649,12 +649,144 @@ def uc_gui_write(driver, text):
pyautogui.write(text)
-def uc_gui_handle_cf(driver, frame="iframe"):
+def get_gui_element_position(driver, selector):
+ element = driver.wait_for_element_present(selector, timeout=3)
+ element_rect = element.rect
+ window_rect = driver.get_window_rect()
+ window_bottom_y = window_rect["y"] + window_rect["height"]
+ viewport_height = driver.execute_script("return window.innerHeight;")
+ viewport_x = window_rect["x"] + element_rect["x"]
+ viewport_y = window_bottom_y - viewport_height + element_rect["y"]
+ return (viewport_x, viewport_y)
+
+
+def uc_gui_click_x_y(driver, x, y, timeframe=0.25, uc_lock=True):
+ install_pyautogui_if_missing(driver)
+ import pyautogui
+ pyautogui = get_configured_pyautogui(pyautogui)
+ screen_width, screen_height = pyautogui.size()
+ if x> screen_width or y> screen_height:
+ raise Exception(
+ "PyAutoGUI cannot click on point (%s, %s)"
+ " outside screen. (Width: %s, Height: %s)"
+ % (x, y, screen_width, screen_height)
+ )
+ if uc_lock:
+ gui_lock = fasteners.InterProcessLock(
+ constants.MultiBrowser.PYAUTOGUILOCK
+ )
+ with gui_lock: # Prevent issues with multiple processes
+ pyautogui.moveTo(x, y, timeframe, pyautogui.easeOutQuad)
+ if timeframe>= 0.25:
+ time.sleep(0.0555) # Wait if moving at human-speed
+ if "--debug" in sys.argv:
+ print("