11
11
import warnings
12
12
from selenium import webdriver
13
13
from selenium .common .exceptions import ElementClickInterceptedException
14
+ from selenium .common .exceptions import InvalidSessionIdException
14
15
from selenium .webdriver .chrome .service import Service as ChromeService
15
16
from selenium .webdriver .common .options import ArgOptions
16
17
from selenium .webdriver .common .service import utils as service_utils
28
29
from seleniumbase .core import sb_driver
29
30
from seleniumbase .fixtures import constants
30
31
from seleniumbase .fixtures import js_utils
32
+ from seleniumbase .fixtures import page_actions
31
33
from seleniumbase .fixtures import shared_utils
32
34
33
35
urllib3 .disable_warnings ()
@@ -409,7 +411,7 @@ def uc_open(driver, url):
409
411
if (url .startswith ("http:" ) or url .startswith ("https:" )):
410
412
with driver :
411
413
script = 'window.location.href = "%s";' % url
412
- js_utils .call_me_later (driver , script , 33 )
414
+ js_utils .call_me_later (driver , script , 5 )
413
415
else :
414
416
driver .default_get (url ) # The original one
415
417
return None
@@ -440,22 +442,28 @@ def uc_open_with_reconnect(driver, url, reconnect_time=None):
440
442
url = "https://" + url
441
443
if (url .startswith ("http:" ) or url .startswith ("https:" )):
442
444
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 )
445
447
driver .close ()
446
448
if reconnect_time == "disconnect" :
447
449
driver .disconnect ()
448
- time .sleep (0.007 )
450
+ time .sleep (0.008 )
449
451
else :
450
452
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 ])
452
459
else :
453
460
driver .default_get (url ) # The original one
454
461
return None
455
462
456
463
457
- def uc_open_with_disconnect (driver , url ):
464
+ def uc_open_with_disconnect (driver , url , timeout = None ):
458
465
"""Open a url and disconnect chromedriver.
466
+ Then waits for the duration of the timeout.
459
467
Note: You can't perform Selenium actions again
460
468
until after you've called driver.connect()."""
461
469
if url .startswith ("//" ):
@@ -464,11 +472,16 @@ def uc_open_with_disconnect(driver, url):
464
472
url = "https://" + url
465
473
if (url .startswith ("http:" ) or url .startswith ("https:" )):
466
474
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 )
469
477
driver .close ()
470
478
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 )
472
485
else :
473
486
driver .default_get (url ) # The original one
474
487
return None
@@ -490,7 +503,7 @@ def uc_click(
490
503
pass
491
504
element = driver .wait_for_selector (selector , by = by , timeout = timeout )
492
505
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"
494
507
element = driver .wait_for_element (selector , by = by , timeout = timeout )
495
508
try :
496
509
element .uc_click (
@@ -509,7 +522,154 @@ def uc_click(
509
522
driver .reconnect (reconnect_time )
510
523
511
524
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 ):
513
673
from selenium .webdriver .remote .webelement import WebElement
514
674
if isinstance (frame , WebElement ):
515
675
if not reconnect_time :
@@ -3822,6 +3982,26 @@ def get_local_driver(
3822
3982
driver .uc_click = lambda * args , ** kwargs : uc_click (
3823
3983
driver , * args , ** kwargs
3824
3984
)
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
+ )
3825
4005
driver .uc_switch_to_frame = (
3826
4006
lambda * args , ** kwargs : uc_switch_to_frame (
3827
4007
driver , * args , ** kwargs
0 commit comments