1111import warnings
1212from selenium import webdriver
1313from selenium .common .exceptions import ElementClickInterceptedException
14+ from selenium .common .exceptions import InvalidSessionIdException
1415from selenium .webdriver .chrome .service import Service as ChromeService
1516from selenium .webdriver .common .options import ArgOptions
1617from selenium .webdriver .common .service import utils as service_utils
2829from seleniumbase .core import sb_driver
2930from seleniumbase .fixtures import constants
3031from seleniumbase .fixtures import js_utils
32+ from seleniumbase .fixtures import page_actions
3133from seleniumbase .fixtures import shared_utils
3234
3335urllib3 .disable_warnings ()
@@ -409,7 +411,7 @@ def uc_open(driver, url):
409411 if (url .startswith ("http:" ) or url .startswith ("https:" )):
410412 with driver :
411413 script = 'window.location.href = "%s";' % url
412- js_utils .call_me_later (driver , script , 33 )
414+ js_utils .call_me_later (driver , script , 5 )
413415 else :
414416 driver .default_get (url ) # The original one
415417 return None
@@ -440,22 +442,28 @@ def uc_open_with_reconnect(driver, url, reconnect_time=None):
440442 url = "https://" + url
441443 if (url .startswith ("http:" ) or url .startswith ("https:" )):
442444 script = 'window.open("%s","_blank");' % url
443- js_utils . call_me_later ( driver , script , 3 )
444- time .sleep (0.007 )
445+ driver . execute_script ( script )
446+ time .sleep (0.05 )
445447 driver .close ()
446448 if reconnect_time == "disconnect" :
447449 driver .disconnect ()
448- time .sleep (0.007 )
450+ time .sleep (0.008 )
449451 else :
450452 driver .reconnect (reconnect_time )
451- driver .switch_to .window (driver .window_handles [- 1 ])
453+ time .sleep (0.004 )
454+ try :
455+ driver .switch_to .window (driver .window_handles [- 1 ])
456+ except InvalidSessionIdException :
457+ time .sleep (0.05 )
458+ driver .switch_to .window (driver .window_handles [- 1 ])
452459 else :
453460 driver .default_get (url ) # The original one
454461 return None
455462
456463
457- def uc_open_with_disconnect (driver , url ):
464+ def uc_open_with_disconnect (driver , url , timeout = None ):
458465 """Open a url and disconnect chromedriver.
466+ Then waits for the duration of the timeout.
459467 Note: You can't perform Selenium actions again
460468 until after you've called driver.connect()."""
461469 if url .startswith ("//" ):
@@ -464,11 +472,16 @@ def uc_open_with_disconnect(driver, url):
464472 url = "https://" + url
465473 if (url .startswith ("http:" ) or url .startswith ("https:" )):
466474 script = 'window.open("%s","_blank");' % url
467- js_utils . call_me_later ( driver , script , 3 )
468- time .sleep (0.007 )
475+ driver . execute_script ( script )
476+ time .sleep (0.05 )
469477 driver .close ()
470478 driver .disconnect ()
471- time .sleep (0.007 )
479+ min_timeout = 0.008
480+ if timeout and not str (timeout ).replace ("." , "" , 1 ).isdigit ():
481+ timeout = min_timeout
482+ if not timeout or timeout < min_timeout :
483+ timeout = min_timeout
484+ time .sleep (timeout )
472485 else :
473486 driver .default_get (url ) # The original one
474487 return None
@@ -490,7 +503,7 @@ def uc_click(
490503 pass
491504 element = driver .wait_for_selector (selector , by = by , timeout = timeout )
492505 tag_name = element .tag_name
493- if not tag_name == "span" : # Element must be "visible"
506+ if not tag_name == "span" and not tag_name == "input" : # Must be "visible"
494507 element = driver .wait_for_element (selector , by = by , timeout = timeout )
495508 try :
496509 element .uc_click (
@@ -509,7 +522,154 @@ def uc_click(
509522 driver .reconnect (reconnect_time )
510523
511524
512- def uc_switch_to_frame (driver , frame , reconnect_time = None ):
525+ def verify_pyautogui_has_a_headed_browser ():
526+ """PyAutoGUI requires a headed browser so that it can
527+ focus on the correct element when performing actions."""
528+ if sb_config .headless or sb_config .headless2 :
529+ raise Exception (
530+ "PyAutoGUI can't be used in headless mode!"
531+ )
532+
533+
534+ def install_pyautogui_if_missing ():
535+ verify_pyautogui_has_a_headed_browser ()
536+ pip_find_lock = fasteners .InterProcessLock (
537+ constants .PipInstall .FINDLOCK
538+ )
539+ with pip_find_lock : # Prevent issues with multiple processes
540+ try :
541+ import pyautogui
542+ try :
543+ use_pyautogui_ver = constants .PyAutoGUI .VER
544+ if pyautogui .__version__ != use_pyautogui_ver :
545+ del pyautogui
546+ shared_utils .pip_install (
547+ "pyautogui" , version = use_pyautogui_ver
548+ )
549+ import pyautogui
550+ except Exception :
551+ pass
552+ except Exception :
553+ print ("\n PyAutoGUI required! Installing now..." )
554+ shared_utils .pip_install (
555+ "pyautogui" , version = constants .PyAutoGUI .VER
556+ )
557+
558+
559+ def get_configured_pyautogui (pyautogui_copy ):
560+ if (
561+ IS_LINUX
562+ and hasattr (pyautogui_copy , "_pyautogui_x11" )
563+ and "DISPLAY" in os .environ .keys ()
564+ ):
565+ if (
566+ hasattr (sb_config , "_pyautogui_x11_display" )
567+ and sb_config ._pyautogui_x11_display
568+ and hasattr (pyautogui_copy ._pyautogui_x11 , "_display" )
569+ and (
570+ sb_config ._pyautogui_x11_display
571+ == pyautogui_copy ._pyautogui_x11 ._display
572+ )
573+ ):
574+ pass
575+ else :
576+ import Xlib .display
577+ pyautogui_copy ._pyautogui_x11 ._display = (
578+ Xlib .display .Display (os .environ ['DISPLAY' ])
579+ )
580+ sb_config ._pyautogui_x11_display = (
581+ pyautogui_copy ._pyautogui_x11 ._display
582+ )
583+ return pyautogui_copy
584+
585+
586+ def uc_gui_press_key (driver , key ):
587+ install_pyautogui_if_missing ()
588+ import pyautogui
589+ pyautogui = get_configured_pyautogui (pyautogui )
590+ gui_lock = fasteners .InterProcessLock (
591+ constants .MultiBrowser .PYAUTOGUILOCK
592+ )
593+ with gui_lock :
594+ pyautogui .press (key )
595+
596+
597+ def uc_gui_press_keys (driver , keys ):
598+ install_pyautogui_if_missing ()
599+ import pyautogui
600+ pyautogui = get_configured_pyautogui (pyautogui )
601+ gui_lock = fasteners .InterProcessLock (
602+ constants .MultiBrowser .PYAUTOGUILOCK
603+ )
604+ with gui_lock :
605+ for key in keys :
606+ pyautogui .press (key )
607+
608+
609+ def uc_gui_write (driver , text ):
610+ install_pyautogui_if_missing ()
611+ import pyautogui
612+ pyautogui = get_configured_pyautogui (pyautogui )
613+ gui_lock = fasteners .InterProcessLock (
614+ constants .MultiBrowser .PYAUTOGUILOCK
615+ )
616+ with gui_lock :
617+ pyautogui .write (text )
618+
619+
620+ def uc_gui_handle_cf (driver , frame = "iframe" ):
621+ source = driver .get_page_source ()
622+ if (
623+ "//challenges.cloudflare.com" not in source
624+ and 'aria-label="Cloudflare"' not in source
625+ ):
626+ return
627+ install_pyautogui_if_missing ()
628+ import pyautogui
629+ pyautogui = get_configured_pyautogui (pyautogui )
630+ gui_lock = fasteners .InterProcessLock (
631+ constants .MultiBrowser .PYAUTOGUILOCK
632+ )
633+ with gui_lock : # Prevent issues with multiple processes
634+ needs_switch = False
635+ is_in_frame = js_utils .is_in_frame (driver )
636+ if is_in_frame and driver .is_element_present ("#challenge-stage" ):
637+ driver .switch_to .parent_frame ()
638+ needs_switch = True
639+ is_in_frame = js_utils .is_in_frame (driver )
640+ if not is_in_frame :
641+ # Make sure the window is on top
642+ page_actions .switch_to_window (
643+ driver ,
644+ driver .current_window_handle ,
645+ timeout = settings .SMALL_TIMEOUT ,
646+ )
647+ if not is_in_frame or needs_switch :
648+ # Currently not in frame (or nested frame outside CF one)
649+ try :
650+ driver .switch_to_frame (frame )
651+ except Exception :
652+ if driver .is_element_present ("iframe" ):
653+ driver .switch_to_frame ("iframe" )
654+ else :
655+ return
656+ try :
657+ driver .execute_script ('document.querySelector("input").focus()' )
658+ except Exception :
659+ try :
660+ driver .switch_to .default_content ()
661+ except Exception :
662+ return
663+ driver .disconnect ()
664+ try :
665+ pyautogui .press (" " )
666+ except Exception :
667+ pass
668+ reconnect_time = (float (constants .UC .RECONNECT_TIME ) / 2.0 ) + 0.5
669+ driver .reconnect (reconnect_time )
670+
671+
672+ def uc_switch_to_frame (driver , frame = "iframe" , reconnect_time = None ):
513673 from selenium .webdriver .remote .webelement import WebElement
514674 if isinstance (frame , WebElement ):
515675 if not reconnect_time :
@@ -3822,6 +3982,26 @@ def get_local_driver(
38223982 driver .uc_click = lambda * args , ** kwargs : uc_click (
38233983 driver , * args , ** kwargs
38243984 )
3985+ driver .uc_gui_press_key = (
3986+ lambda * args , ** kwargs : uc_gui_press_key (
3987+ driver , * args , ** kwargs
3988+ )
3989+ )
3990+ driver .uc_gui_press_keys = (
3991+ lambda * args , ** kwargs : uc_gui_press_keys (
3992+ driver , * args , ** kwargs
3993+ )
3994+ )
3995+ driver .uc_gui_write = (
3996+ lambda * args , ** kwargs : uc_gui_write (
3997+ driver , * args , ** kwargs
3998+ )
3999+ )
4000+ driver .uc_gui_handle_cf = (
4001+ lambda * args , ** kwargs : uc_gui_handle_cf (
4002+ driver , * args , ** kwargs
4003+ )
4004+ )
38254005 driver .uc_switch_to_frame = (
38264006 lambda * args , ** kwargs : uc_switch_to_frame (
38274007 driver , * args , ** kwargs
0 commit comments