Skip to content

Commit ac3a9be

Browse files
committed
Add UC Mode clicking methods
1 parent 1c526f1 commit ac3a9be

File tree

2 files changed

+151
-3
lines changed

2 files changed

+151
-3
lines changed

seleniumbase/core/browser_launcher.py

Lines changed: 147 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -649,12 +649,144 @@ def uc_gui_write(driver, text):
649649
pyautogui.write(text)
650650

651651

652-
def uc_gui_handle_cf(driver, frame="iframe"):
652+
def get_gui_element_position(driver, selector):
653+
element = driver.wait_for_element_present(selector, timeout=3)
654+
element_rect = element.rect
655+
window_rect = driver.get_window_rect()
656+
window_bottom_y = window_rect["y"] + window_rect["height"]
657+
viewport_height = driver.execute_script("return window.innerHeight;")
658+
viewport_x = window_rect["x"] + element_rect["x"]
659+
viewport_y = window_bottom_y - viewport_height + element_rect["y"]
660+
return (viewport_x, viewport_y)
661+
662+
663+
def uc_gui_click_x_y(driver, x, y, timeframe=0.25, uc_lock=True):
664+
install_pyautogui_if_missing(driver)
665+
import pyautogui
666+
pyautogui = get_configured_pyautogui(pyautogui)
667+
screen_width, screen_height = pyautogui.size()
668+
if x > screen_width or y > screen_height:
669+
raise Exception(
670+
"PyAutoGUI cannot click on point (%s, %s)"
671+
" outside screen. (Width: %s, Height: %s)"
672+
% (x, y, screen_width, screen_height)
673+
)
674+
if uc_lock:
675+
gui_lock = fasteners.InterProcessLock(
676+
constants.MultiBrowser.PYAUTOGUILOCK
677+
)
678+
with gui_lock: # Prevent issues with multiple processes
679+
pyautogui.moveTo(x, y, timeframe, pyautogui.easeOutQuad)
680+
if timeframe >= 0.25:
681+
time.sleep(0.0555) # Wait if moving at human-speed
682+
if "--debug" in sys.argv:
683+
print(" <DEBUG> pyautogui.click(%s, %s)" % (x, y))
684+
pyautogui.click(x=x, y=y)
685+
else:
686+
# Called from a method where the gui_lock is already active
687+
pyautogui.moveTo(x, y, timeframe, pyautogui.easeOutQuad)
688+
if timeframe >= 0.25:
689+
time.sleep(0.0555) # Wait if moving at human-speed
690+
if "--debug" in sys.argv:
691+
print(" <DEBUG> pyautogui.click(%s, %s)" % (x, y))
692+
pyautogui.click(x=x, y=y)
693+
694+
695+
def on_a_cf_turnstile_page(driver):
653696
source = driver.get_page_source()
654697
if (
655-
"//challenges.cloudflare.com" not in source
656-
and 'aria-label="Cloudflare"' not in source
698+
"//challenges.cloudflare.com" in source
699+
or 'aria-label="Cloudflare"' in source
657700
):
701+
return True
702+
return False
703+
704+
705+
def uc_gui_click_cf(driver, frame="iframe", retry=False, blind=False):
706+
if not on_a_cf_turnstile_page(driver):
707+
return
708+
install_pyautogui_if_missing(driver)
709+
import pyautogui
710+
pyautogui = get_configured_pyautogui(pyautogui)
711+
x = None
712+
y = None
713+
gui_lock = fasteners.InterProcessLock(
714+
constants.MultiBrowser.PYAUTOGUILOCK
715+
)
716+
with gui_lock: # Prevent issues with multiple processes
717+
needs_switch = False
718+
is_in_frame = js_utils.is_in_frame(driver)
719+
if is_in_frame and driver.is_element_present("#challenge-stage"):
720+
driver.switch_to.parent_frame()
721+
needs_switch = True
722+
is_in_frame = js_utils.is_in_frame(driver)
723+
if not is_in_frame:
724+
# Make sure the window is on top
725+
page_actions.switch_to_window(
726+
driver, driver.current_window_handle, 2, uc_lock=False
727+
)
728+
if not is_in_frame or needs_switch:
729+
# Currently not in frame (or nested frame outside CF one)
730+
try:
731+
i_x, i_y = get_gui_element_position(driver, "iframe")
732+
driver.switch_to_frame(frame)
733+
except Exception:
734+
if driver.is_element_present("iframe"):
735+
i_x, i_y = get_gui_element_position(driver, "iframe")
736+
driver.switch_to_frame("iframe")
737+
else:
738+
return
739+
try:
740+
selector = "span"
741+
element = driver.wait_for_element_present(selector, timeout=2.5)
742+
x = i_x + element.rect["x"] + int(element.rect["width"] / 2) + 1
743+
y = i_y + element.rect["y"] + int(element.rect["height"] / 2) + 1
744+
driver.switch_to.default_content()
745+
except Exception:
746+
try:
747+
driver.switch_to.default_content()
748+
except Exception:
749+
return
750+
driver.disconnect()
751+
try:
752+
if x and y:
753+
sb_config._saved_cf_x_y = (x, y)
754+
uc_gui_click_x_y(driver, x, y, timeframe=0.842, uc_lock=False)
755+
except Exception:
756+
pass
757+
reconnect_time = (float(constants.UC.RECONNECT_TIME) / 2.0) + 0.5
758+
if IS_LINUX:
759+
reconnect_time = constants.UC.RECONNECT_TIME
760+
if not x or not y:
761+
reconnect_time = 1 # Make it quick (it already failed)
762+
driver.reconnect(reconnect_time)
763+
if blind:
764+
retry = True
765+
if retry and x and y and on_a_cf_turnstile_page(driver):
766+
with gui_lock: # Prevent issues with multiple processes
767+
# Make sure the window is on top
768+
page_actions.switch_to_window(
769+
driver, driver.current_window_handle, 2, uc_lock=False
770+
)
771+
driver.switch_to_frame("iframe")
772+
if driver.is_element_visible("#success-icon"):
773+
driver.switch_to.parent_frame()
774+
return
775+
if blind:
776+
driver.uc_open_with_disconnect(driver.current_url, 3.8)
777+
uc_gui_click_x_y(driver, x, y, timeframe=1.05, uc_lock=False)
778+
else:
779+
driver.uc_open_with_reconnect(driver.current_url, 3.8)
780+
if on_a_cf_turnstile_page(driver):
781+
driver.disconnect()
782+
uc_gui_click_x_y(
783+
driver, x, y, timeframe=1.05, uc_lock=False
784+
)
785+
driver.reconnect(reconnect_time)
786+
787+
788+
def uc_gui_handle_cf(driver, frame="iframe"):
789+
if not on_a_cf_turnstile_page(driver):
658790
return
659791
install_pyautogui_if_missing(driver)
660792
import pyautogui
@@ -696,6 +828,8 @@ def uc_gui_handle_cf(driver, frame="iframe"):
696828
except Exception:
697829
pass
698830
reconnect_time = (float(constants.UC.RECONNECT_TIME) / 2.0) + 0.5
831+
if IS_LINUX:
832+
reconnect_time = constants.UC.RECONNECT_TIME
699833
driver.reconnect(reconnect_time)
700834

701835

@@ -4027,6 +4161,16 @@ def get_local_driver(
40274161
driver, *args, **kwargs
40284162
)
40294163
)
4164+
driver.uc_gui_click_x_y = (
4165+
lambda *args, **kwargs: uc_gui_click_x_y(
4166+
driver, *args, **kwargs
4167+
)
4168+
)
4169+
driver.uc_gui_click_cf = (
4170+
lambda *args, **kwargs: uc_gui_click_cf(
4171+
driver, *args, **kwargs
4172+
)
4173+
)
40304174
driver.uc_gui_handle_cf = (
40314175
lambda *args, **kwargs: uc_gui_handle_cf(
40324176
driver, *args, **kwargs

seleniumbase/fixtures/base_case.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4178,6 +4178,10 @@ def get_new_driver(
41784178
self.uc_gui_press_keys = new_driver.uc_gui_press_keys
41794179
if hasattr(new_driver, "uc_gui_write"):
41804180
self.uc_gui_write = new_driver.uc_gui_write
4181+
if hasattr(new_driver, "uc_gui_click_x_y"):
4182+
self.uc_gui_click_x_y = new_driver.uc_gui_click_x_y
4183+
if hasattr(new_driver, "uc_gui_click_cf"):
4184+
self.uc_gui_click_cf = new_driver.uc_gui_click_cf
41814185
if hasattr(new_driver, "uc_gui_handle_cf"):
41824186
self.uc_gui_handle_cf = new_driver.uc_gui_handle_cf
41834187
if hasattr(new_driver, "uc_switch_to_frame"):

0 commit comments

Comments
 (0)