seleniumbase 4.41.3__py3-none-any.whl → 4.45.10__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- sbase/steps.py +9 -0
- seleniumbase/__version__.py +1 -1
- seleniumbase/behave/behave_helper.py +2 -0
- seleniumbase/behave/behave_sb.py +21 -8
- seleniumbase/common/decorators.py +3 -1
- seleniumbase/console_scripts/run.py +1 -0
- seleniumbase/console_scripts/sb_caseplans.py +3 -4
- seleniumbase/console_scripts/sb_install.py +142 -11
- seleniumbase/console_scripts/sb_mkchart.py +1 -2
- seleniumbase/console_scripts/sb_mkdir.py +99 -29
- seleniumbase/console_scripts/sb_mkfile.py +1 -2
- seleniumbase/console_scripts/sb_mkpres.py +1 -2
- seleniumbase/console_scripts/sb_mkrec.py +26 -2
- seleniumbase/console_scripts/sb_objectify.py +4 -5
- seleniumbase/console_scripts/sb_print.py +1 -1
- seleniumbase/console_scripts/sb_recorder.py +40 -3
- seleniumbase/core/browser_launcher.py +474 -151
- seleniumbase/core/detect_b_ver.py +258 -16
- seleniumbase/core/log_helper.py +15 -21
- seleniumbase/core/mysql.py +1 -1
- seleniumbase/core/recorder_helper.py +3 -0
- seleniumbase/core/report_helper.py +9 -12
- seleniumbase/core/sb_cdp.py +734 -215
- seleniumbase/core/sb_driver.py +46 -5
- seleniumbase/core/session_helper.py +2 -4
- seleniumbase/core/tour_helper.py +1 -2
- seleniumbase/drivers/atlas_drivers/__init__.py +0 -0
- seleniumbase/drivers/brave_drivers/__init__.py +0 -0
- seleniumbase/drivers/chromium_drivers/__init__.py +0 -0
- seleniumbase/drivers/comet_drivers/__init__.py +0 -0
- seleniumbase/drivers/opera_drivers/__init__.py +0 -0
- seleniumbase/fixtures/base_case.py +448 -251
- seleniumbase/fixtures/constants.py +36 -9
- seleniumbase/fixtures/js_utils.py +77 -18
- seleniumbase/fixtures/page_actions.py +41 -13
- seleniumbase/fixtures/page_utils.py +19 -12
- seleniumbase/fixtures/shared_utils.py +64 -6
- seleniumbase/masterqa/master_qa.py +16 -2
- seleniumbase/plugins/base_plugin.py +8 -0
- seleniumbase/plugins/basic_test_info.py +2 -3
- seleniumbase/plugins/driver_manager.py +131 -5
- seleniumbase/plugins/page_source.py +2 -3
- seleniumbase/plugins/pytest_plugin.py +244 -79
- seleniumbase/plugins/sb_manager.py +143 -20
- seleniumbase/plugins/selenium_plugin.py +144 -12
- seleniumbase/translate/translator.py +2 -3
- seleniumbase/undetected/__init__.py +17 -13
- seleniumbase/undetected/cdp.py +1 -12
- seleniumbase/undetected/cdp_driver/browser.py +330 -129
- seleniumbase/undetected/cdp_driver/cdp_util.py +328 -61
- seleniumbase/undetected/cdp_driver/config.py +110 -14
- seleniumbase/undetected/cdp_driver/connection.py +18 -48
- seleniumbase/undetected/cdp_driver/element.py +105 -33
- seleniumbase/undetected/cdp_driver/tab.py +414 -39
- seleniumbase/utilities/selenium_grid/download_selenium_server.py +1 -1
- seleniumbase/utilities/selenium_grid/grid_hub.py +1 -2
- seleniumbase/utilities/selenium_grid/grid_node.py +2 -3
- seleniumbase/utilities/selenium_ide/convert_ide.py +2 -3
- {seleniumbase-4.41.3.dist-info → seleniumbase-4.45.10.dist-info}/METADATA +193 -166
- {seleniumbase-4.41.3.dist-info → seleniumbase-4.45.10.dist-info}/RECORD +64 -59
- {seleniumbase-4.41.3.dist-info → seleniumbase-4.45.10.dist-info}/licenses/LICENSE +1 -1
- {seleniumbase-4.41.3.dist-info → seleniumbase-4.45.10.dist-info}/WHEEL +0 -0
- {seleniumbase-4.41.3.dist-info → seleniumbase-4.45.10.dist-info}/entry_points.txt +0 -0
- {seleniumbase-4.41.3.dist-info → seleniumbase-4.45.10.dist-info}/top_level.txt +0 -0
|
@@ -12,6 +12,7 @@ import types
|
|
|
12
12
|
import urllib3
|
|
13
13
|
import warnings
|
|
14
14
|
from contextlib import suppress
|
|
15
|
+
from filelock import FileLock
|
|
15
16
|
from selenium import webdriver
|
|
16
17
|
from selenium.common.exceptions import ElementClickInterceptedException
|
|
17
18
|
from selenium.common.exceptions import InvalidSessionIdException
|
|
@@ -27,6 +28,11 @@ from seleniumbase import decorators
|
|
|
27
28
|
from seleniumbase import drivers # webdriver storage folder for SeleniumBase
|
|
28
29
|
from seleniumbase.drivers import cft_drivers # chrome-for-testing
|
|
29
30
|
from seleniumbase.drivers import chs_drivers # chrome-headless-shell
|
|
31
|
+
from seleniumbase.drivers import opera_drivers # still uses chromedriver
|
|
32
|
+
from seleniumbase.drivers import brave_drivers # still uses chromedriver
|
|
33
|
+
from seleniumbase.drivers import comet_drivers # still uses chromedriver
|
|
34
|
+
from seleniumbase.drivers import atlas_drivers # still uses chromedriver
|
|
35
|
+
from seleniumbase.drivers import chromium_drivers # still uses chromedriver
|
|
30
36
|
from seleniumbase import extensions # browser extensions storage folder
|
|
31
37
|
from seleniumbase.config import settings
|
|
32
38
|
from seleniumbase.core import detect_b_ver
|
|
@@ -43,6 +49,13 @@ urllib3.disable_warnings()
|
|
|
43
49
|
DRIVER_DIR = os.path.dirname(os.path.realpath(drivers.__file__))
|
|
44
50
|
DRIVER_DIR_CFT = os.path.dirname(os.path.realpath(cft_drivers.__file__))
|
|
45
51
|
DRIVER_DIR_CHS = os.path.dirname(os.path.realpath(chs_drivers.__file__))
|
|
52
|
+
DRIVER_DIR_OPERA = os.path.dirname(os.path.realpath(opera_drivers.__file__))
|
|
53
|
+
DRIVER_DIR_BRAVE = os.path.dirname(os.path.realpath(brave_drivers.__file__))
|
|
54
|
+
DRIVER_DIR_COMET = os.path.dirname(os.path.realpath(comet_drivers.__file__))
|
|
55
|
+
DRIVER_DIR_ATLAS = os.path.dirname(os.path.realpath(atlas_drivers.__file__))
|
|
56
|
+
DRIVER_DIR_CHROMIUM = os.path.dirname(
|
|
57
|
+
os.path.realpath(chromium_drivers.__file__)
|
|
58
|
+
)
|
|
46
59
|
# Make sure that the SeleniumBase DRIVER_DIR is at the top of the System PATH
|
|
47
60
|
# (Changes to the System PATH with os.environ only last during the test run)
|
|
48
61
|
if not os.environ["PATH"].startswith(DRIVER_DIR):
|
|
@@ -95,10 +108,7 @@ else:
|
|
|
95
108
|
def log_d(message):
|
|
96
109
|
"""If setting sb_config.settings.HIDE_DRIVER_DOWNLOADS to True,
|
|
97
110
|
output from driver downloads are logged instead of printed."""
|
|
98
|
-
if (
|
|
99
|
-
hasattr(settings, "HIDE_DRIVER_DOWNLOADS")
|
|
100
|
-
and settings.HIDE_DRIVER_DOWNLOADS
|
|
101
|
-
):
|
|
111
|
+
if getattr(settings, "HIDE_DRIVER_DOWNLOADS", None):
|
|
102
112
|
logging.debug(message)
|
|
103
113
|
else:
|
|
104
114
|
print(message)
|
|
@@ -150,9 +160,21 @@ def extend_driver(
|
|
|
150
160
|
# Extend the driver with new methods
|
|
151
161
|
driver.default_find_element = driver.find_element
|
|
152
162
|
driver.default_find_elements = driver.find_elements
|
|
163
|
+
driver.default_add_cookie = driver.add_cookie
|
|
164
|
+
driver.default_get_cookie = driver.get_cookie
|
|
165
|
+
driver.default_delete_cookie = driver.delete_cookie
|
|
166
|
+
driver.default_back = driver.back
|
|
167
|
+
driver.default_forward = driver.forward
|
|
168
|
+
driver.default_refresh = driver.refresh
|
|
153
169
|
DM = sb_driver.DriverMethods(driver)
|
|
154
170
|
driver.find_element = DM.find_element
|
|
155
171
|
driver.find_elements = DM.find_elements
|
|
172
|
+
driver.add_cookie = DM.add_cookie
|
|
173
|
+
driver.get_cookie = DM.get_cookie
|
|
174
|
+
driver.delete_cookie = DM.delete_cookie
|
|
175
|
+
driver.back = DM.back
|
|
176
|
+
driver.forward = DM.forward
|
|
177
|
+
driver.refresh = DM.refresh
|
|
156
178
|
driver.locator = DM.locator
|
|
157
179
|
page = types.SimpleNamespace()
|
|
158
180
|
page.open = DM.open_url
|
|
@@ -227,6 +249,8 @@ def extend_driver(
|
|
|
227
249
|
driver.wait_for_element = DM.wait_for_element
|
|
228
250
|
driver.wait_for_element_visible = DM.wait_for_element_visible
|
|
229
251
|
driver.wait_for_element_present = DM.wait_for_element_present
|
|
252
|
+
driver.wait_for_element_absent = DM.wait_for_element_absent
|
|
253
|
+
driver.wait_for_element_not_visible = DM.wait_for_element_not_visible
|
|
230
254
|
driver.wait_for_selector = DM.wait_for_selector
|
|
231
255
|
driver.wait_for_text = DM.wait_for_text
|
|
232
256
|
driver.wait_for_exact_text = DM.wait_for_exact_text
|
|
@@ -282,7 +306,19 @@ def extend_driver(
|
|
|
282
306
|
)
|
|
283
307
|
if hasattr(driver, "proxy"):
|
|
284
308
|
driver.set_wire_proxy = DM.set_wire_proxy
|
|
309
|
+
completed_loads = []
|
|
310
|
+
for ext_dir in sb_config._ext_dirs:
|
|
311
|
+
if ext_dir not in completed_loads:
|
|
312
|
+
completed_loads.append(ext_dir)
|
|
313
|
+
if not use_uc and os.path.exists(os.path.realpath(ext_dir)):
|
|
314
|
+
with suppress(Exception):
|
|
315
|
+
driver.webextension.install(os.path.realpath(ext_dir))
|
|
316
|
+
driver._is_using_auth = False
|
|
285
317
|
if proxy_auth:
|
|
318
|
+
driver._is_using_auth = True
|
|
319
|
+
if not use_uc and os.path.exists(proxy_helper.PROXY_DIR_PATH):
|
|
320
|
+
with suppress(Exception):
|
|
321
|
+
driver.webextension.install(proxy_helper.PROXY_DIR_PATH)
|
|
286
322
|
# Proxy needs a moment to load in Manifest V3
|
|
287
323
|
if use_uc:
|
|
288
324
|
time.sleep(0.14)
|
|
@@ -408,16 +444,16 @@ def has_captcha(text):
|
|
|
408
444
|
"<title>403 Forbidden</title>" in text
|
|
409
445
|
or "Permission Denied</title>" in text
|
|
410
446
|
or 'id="challenge-error-text"' in text
|
|
447
|
+
or "/challenge-platform/h/b/" in text
|
|
411
448
|
or "<title>Just a moment..." in text
|
|
412
449
|
or 'action="/?__cf_chl_f_tk' in text
|
|
413
450
|
or 'id="challenge-widget-' in text
|
|
414
451
|
or 'src="chromedriver.js"' in text
|
|
452
|
+
or "com/recaptcha/api.js" in text
|
|
415
453
|
or 'class="g-recaptcha"' in text
|
|
416
454
|
or 'content="Pixelscan"' in text
|
|
417
455
|
or 'id="challenge-form"' in text
|
|
418
|
-
or "/challenge-platform" in text
|
|
419
456
|
or "window._cf_chl_opt" in text
|
|
420
|
-
or "/recaptcha/api.js" in text
|
|
421
457
|
or "/turnstile/" in text
|
|
422
458
|
):
|
|
423
459
|
return True
|
|
@@ -429,6 +465,18 @@ def __is_cdp_swap_needed(driver):
|
|
|
429
465
|
return shared_utils.is_cdp_swap_needed(driver)
|
|
430
466
|
|
|
431
467
|
|
|
468
|
+
def uc_execute_cdp_cmd(driver, *args, **kwargs):
|
|
469
|
+
if not driver.is_connected():
|
|
470
|
+
driver.connect()
|
|
471
|
+
return driver.default_execute_cdp_cmd(*args, **kwargs)
|
|
472
|
+
|
|
473
|
+
|
|
474
|
+
def updated_get(driver, url):
|
|
475
|
+
if url and ":" not in url and "." in url:
|
|
476
|
+
url = "https:" + url
|
|
477
|
+
driver.default_get(url)
|
|
478
|
+
|
|
479
|
+
|
|
432
480
|
def uc_special_open_if_cf(
|
|
433
481
|
driver,
|
|
434
482
|
url,
|
|
@@ -438,6 +486,8 @@ def uc_special_open_if_cf(
|
|
|
438
486
|
device_height=None,
|
|
439
487
|
device_pixel_ratio=None,
|
|
440
488
|
):
|
|
489
|
+
if url and ":" not in url and "." in url:
|
|
490
|
+
url = "https:" + url
|
|
441
491
|
if url.startswith("http:") or url.startswith("https:"):
|
|
442
492
|
special = False
|
|
443
493
|
with suppress(Exception):
|
|
@@ -534,6 +584,19 @@ def uc_open_with_tab(driver, url):
|
|
|
534
584
|
|
|
535
585
|
def uc_open_with_reconnect(driver, url, reconnect_time=None):
|
|
536
586
|
"""Open a url, disconnect chromedriver, wait, and reconnect."""
|
|
587
|
+
if (
|
|
588
|
+
hasattr(sb_config, "_cdp_browser")
|
|
589
|
+
and sb_config._cdp_browser in ["comet", "opera", "atlas"]
|
|
590
|
+
):
|
|
591
|
+
if not __is_cdp_swap_needed(driver):
|
|
592
|
+
if not driver.current_url.startswith(
|
|
593
|
+
("about", "data", "chrome")
|
|
594
|
+
):
|
|
595
|
+
driver.get("about:blank")
|
|
596
|
+
uc_activate_cdp_mode(driver, url)
|
|
597
|
+
else:
|
|
598
|
+
driver.cdp.open(url)
|
|
599
|
+
return
|
|
537
600
|
url = shared_utils.fix_url_as_needed(url)
|
|
538
601
|
if __is_cdp_swap_needed(driver):
|
|
539
602
|
driver.cdp.get(url)
|
|
@@ -594,10 +657,8 @@ def uc_open_with_cdp_mode(driver, url=None, **kwargs):
|
|
|
594
657
|
safe_url = False
|
|
595
658
|
|
|
596
659
|
if (
|
|
597
|
-
|
|
598
|
-
and driver
|
|
599
|
-
and hasattr(driver, "cdp")
|
|
600
|
-
and driver.cdp
|
|
660
|
+
getattr(driver, "_is_using_cdp", None)
|
|
661
|
+
and getattr(driver, "cdp", None)
|
|
601
662
|
and hasattr(driver.cdp, "loop")
|
|
602
663
|
):
|
|
603
664
|
# CDP Mode was already initialized
|
|
@@ -637,11 +698,12 @@ def uc_open_with_cdp_mode(driver, url=None, **kwargs):
|
|
|
637
698
|
xvfb=xvfb,
|
|
638
699
|
xvfb_metrics=xvfb_metrics,
|
|
639
700
|
browser_executable_path=binary_location,
|
|
701
|
+
mobile=getattr(sb_config, "_cdp_mobile_mode", None),
|
|
640
702
|
)
|
|
641
703
|
)
|
|
642
704
|
loop.run_until_complete(driver.cdp_base.wait(0))
|
|
643
705
|
|
|
644
|
-
gui_lock =
|
|
706
|
+
gui_lock = FileLock(constants.MultiBrowser.PYAUTOGUILOCK)
|
|
645
707
|
|
|
646
708
|
if (
|
|
647
709
|
"chrome-extension://" in str(driver.cdp_base.main_tab)
|
|
@@ -700,6 +762,11 @@ def uc_open_with_cdp_mode(driver, url=None, **kwargs):
|
|
|
700
762
|
cdp.refresh = CDPM.refresh
|
|
701
763
|
cdp.add_handler = CDPM.add_handler
|
|
702
764
|
cdp.get_event_loop = CDPM.get_event_loop
|
|
765
|
+
cdp.get_rd_host = CDPM.get_rd_host
|
|
766
|
+
cdp.get_rd_port = CDPM.get_rd_port
|
|
767
|
+
cdp.get_rd_url = CDPM.get_rd_url
|
|
768
|
+
cdp.get_endpoint_url = CDPM.get_endpoint_url
|
|
769
|
+
cdp.get_port = CDPM.get_port
|
|
703
770
|
cdp.find_element = CDPM.find_element
|
|
704
771
|
cdp.find = CDPM.find_element
|
|
705
772
|
cdp.locator = CDPM.find_element
|
|
@@ -734,6 +801,7 @@ def uc_open_with_cdp_mode(driver, url=None, **kwargs):
|
|
|
734
801
|
cdp.click_active_element = CDPM.click_active_element
|
|
735
802
|
cdp.click_if_visible = CDPM.click_if_visible
|
|
736
803
|
cdp.click_visible_elements = CDPM.click_visible_elements
|
|
804
|
+
cdp.click_with_offset = CDPM.click_with_offset
|
|
737
805
|
cdp.mouse_click = CDPM.mouse_click
|
|
738
806
|
cdp.get_parent = CDPM.get_parent
|
|
739
807
|
cdp.remove_element = CDPM.remove_element
|
|
@@ -747,21 +815,30 @@ def uc_open_with_cdp_mode(driver, url=None, **kwargs):
|
|
|
747
815
|
cdp.set_value = CDPM.set_value
|
|
748
816
|
cdp.submit = CDPM.submit
|
|
749
817
|
cdp.evaluate = CDPM.evaluate
|
|
818
|
+
cdp.execute_script = CDPM.execute_script
|
|
750
819
|
cdp.js_dumps = CDPM.js_dumps
|
|
751
820
|
cdp.maximize = CDPM.maximize
|
|
752
821
|
cdp.minimize = CDPM.minimize
|
|
753
822
|
cdp.medimize = CDPM.medimize
|
|
754
823
|
cdp.set_window_rect = CDPM.set_window_rect
|
|
755
824
|
cdp.reset_window_size = CDPM.reset_window_size
|
|
825
|
+
cdp.activate_messenger = CDPM.activate_messenger
|
|
826
|
+
cdp.set_messenger_theme = CDPM.set_messenger_theme
|
|
827
|
+
cdp.post_message = CDPM.post_message
|
|
756
828
|
cdp.set_locale = CDPM.set_locale
|
|
757
829
|
cdp.set_local_storage_item = CDPM.set_local_storage_item
|
|
758
830
|
cdp.set_session_storage_item = CDPM.set_session_storage_item
|
|
759
831
|
cdp.set_attributes = CDPM.set_attributes
|
|
832
|
+
cdp.is_attribute_present = CDPM.is_attribute_present
|
|
833
|
+
cdp.is_online = CDPM.is_online
|
|
834
|
+
cdp.solve_captcha = CDPM.solve_captcha
|
|
835
|
+
cdp.click_captcha = CDPM.click_captcha
|
|
760
836
|
cdp.gui_press_key = CDPM.gui_press_key
|
|
761
837
|
cdp.gui_press_keys = CDPM.gui_press_keys
|
|
762
838
|
cdp.gui_write = CDPM.gui_write
|
|
763
839
|
cdp.gui_click_x_y = CDPM.gui_click_x_y
|
|
764
840
|
cdp.gui_click_element = CDPM.gui_click_element
|
|
841
|
+
cdp.gui_click_with_offset = CDPM.gui_click_with_offset
|
|
765
842
|
cdp.gui_click_captcha = CDPM.gui_click_captcha
|
|
766
843
|
cdp.gui_drag_drop_points = CDPM.gui_drag_drop_points
|
|
767
844
|
cdp.gui_drag_and_drop = CDPM.gui_drag_and_drop
|
|
@@ -769,6 +846,8 @@ def uc_open_with_cdp_mode(driver, url=None, **kwargs):
|
|
|
769
846
|
cdp.gui_hover_x_y = CDPM.gui_hover_x_y
|
|
770
847
|
cdp.gui_hover_element = CDPM.gui_hover_element
|
|
771
848
|
cdp.gui_hover_and_click = CDPM.gui_hover_and_click
|
|
849
|
+
cdp.hover_element = CDPM.hover_element
|
|
850
|
+
cdp.hover_and_click = CDPM.hover_and_click
|
|
772
851
|
cdp.internalize_links = CDPM.internalize_links
|
|
773
852
|
cdp.open_new_window = CDPM.open_new_window
|
|
774
853
|
cdp.switch_to_window = CDPM.switch_to_window
|
|
@@ -789,6 +868,7 @@ def uc_open_with_cdp_mode(driver, url=None, **kwargs):
|
|
|
789
868
|
cdp.get_element_position = CDPM.get_element_position
|
|
790
869
|
cdp.get_gui_element_rect = CDPM.get_gui_element_rect
|
|
791
870
|
cdp.get_gui_element_center = CDPM.get_gui_element_center
|
|
871
|
+
cdp.get_html = CDPM.get_html
|
|
792
872
|
cdp.get_page_source = CDPM.get_page_source
|
|
793
873
|
cdp.get_user_agent = CDPM.get_user_agent
|
|
794
874
|
cdp.get_cookie_string = CDPM.get_cookie_string
|
|
@@ -806,8 +886,12 @@ def uc_open_with_cdp_mode(driver, url=None, **kwargs):
|
|
|
806
886
|
cdp.get_screen_rect = CDPM.get_screen_rect
|
|
807
887
|
cdp.get_window_rect = CDPM.get_window_rect
|
|
808
888
|
cdp.get_window_size = CDPM.get_window_size
|
|
889
|
+
cdp.get_mfa_code = CDPM.get_mfa_code
|
|
809
890
|
cdp.nested_click = CDPM.nested_click
|
|
810
891
|
cdp.select_option_by_text = CDPM.select_option_by_text
|
|
892
|
+
cdp.select_option_by_index = CDPM.select_option_by_index
|
|
893
|
+
cdp.select_option_by_value = CDPM.select_option_by_value
|
|
894
|
+
cdp.enter_mfa_code = CDPM.enter_mfa_code
|
|
811
895
|
cdp.flash = CDPM.flash
|
|
812
896
|
cdp.highlight = CDPM.highlight
|
|
813
897
|
cdp.focus = CDPM.focus
|
|
@@ -826,6 +910,7 @@ def uc_open_with_cdp_mode(driver, url=None, **kwargs):
|
|
|
826
910
|
cdp.wait_for_text = CDPM.wait_for_text
|
|
827
911
|
cdp.wait_for_text_not_visible = CDPM.wait_for_text_not_visible
|
|
828
912
|
cdp.wait_for_element_visible = CDPM.wait_for_element_visible
|
|
913
|
+
cdp.wait_for_element = CDPM.wait_for_element
|
|
829
914
|
cdp.wait_for_element_not_visible = CDPM.wait_for_element_not_visible
|
|
830
915
|
cdp.wait_for_element_absent = CDPM.wait_for_element_absent
|
|
831
916
|
cdp.wait_for_any_of_elements_visible = (
|
|
@@ -857,12 +942,16 @@ def uc_open_with_cdp_mode(driver, url=None, **kwargs):
|
|
|
857
942
|
cdp.assert_not_in = CDPM.assert_not_in
|
|
858
943
|
cdp.scroll_into_view = CDPM.scroll_into_view
|
|
859
944
|
cdp.scroll_to_y = CDPM.scroll_to_y
|
|
945
|
+
cdp.scroll_by_y = CDPM.scroll_by_y
|
|
860
946
|
cdp.scroll_to_top = CDPM.scroll_to_top
|
|
861
947
|
cdp.scroll_to_bottom = CDPM.scroll_to_bottom
|
|
862
948
|
cdp.scroll_up = CDPM.scroll_up
|
|
863
949
|
cdp.scroll_down = CDPM.scroll_down
|
|
950
|
+
cdp.save_page_source = CDPM.save_page_source
|
|
951
|
+
cdp.save_as_html = CDPM.save_as_html
|
|
864
952
|
cdp.save_screenshot = CDPM.save_screenshot
|
|
865
953
|
cdp.print_to_pdf = CDPM.print_to_pdf
|
|
954
|
+
cdp.save_as_pdf = CDPM.save_as_pdf
|
|
866
955
|
cdp.page = page # async world
|
|
867
956
|
cdp.driver = driver.cdp_base # async world
|
|
868
957
|
cdp.tab = cdp.page # shortcut (original)
|
|
@@ -876,7 +965,17 @@ def uc_open_with_cdp_mode(driver, url=None, **kwargs):
|
|
|
876
965
|
cdp.core = core_items
|
|
877
966
|
cdp.loop = cdp.get_event_loop()
|
|
878
967
|
driver.cdp = cdp
|
|
968
|
+
driver.solve_captcha = CDPM.solve_captcha
|
|
969
|
+
driver.click_captcha = CDPM.click_captcha
|
|
970
|
+
driver.find_element_by_text = CDPM.find_element_by_text
|
|
879
971
|
driver._is_using_cdp = True
|
|
972
|
+
if (
|
|
973
|
+
getattr(sb_config, "_cdp_proxy", None)
|
|
974
|
+
and "@" in sb_config._cdp_proxy
|
|
975
|
+
):
|
|
976
|
+
time.sleep(0.077)
|
|
977
|
+
loop.run_until_complete(page.wait(0.25))
|
|
978
|
+
time.sleep(0.022)
|
|
880
979
|
|
|
881
980
|
|
|
882
981
|
def uc_activate_cdp_mode(driver, url=None, **kwargs):
|
|
@@ -951,7 +1050,7 @@ def uc_click(
|
|
|
951
1050
|
def verify_pyautogui_has_a_headed_browser(driver):
|
|
952
1051
|
"""PyAutoGUI requires a headed browser so that it can
|
|
953
1052
|
focus on the correct element when performing actions."""
|
|
954
|
-
if
|
|
1053
|
+
if getattr(driver, "_is_hidden", None):
|
|
955
1054
|
raise Exception(
|
|
956
1055
|
"PyAutoGUI can't be used in headless mode!"
|
|
957
1056
|
)
|
|
@@ -962,17 +1061,15 @@ def __install_pyautogui_if_missing():
|
|
|
962
1061
|
import pyautogui
|
|
963
1062
|
with suppress(Exception):
|
|
964
1063
|
use_pyautogui_ver = constants.PyAutoGUI.VER
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
)
|
|
1064
|
+
u_pv = shared_utils.make_version_tuple(use_pyautogui_ver)
|
|
1065
|
+
pv = shared_utils.make_version_tuple(pyautogui.__version__)
|
|
1066
|
+
if pv < u_pv:
|
|
1067
|
+
del pyautogui # To get newer ver
|
|
1068
|
+
shared_utils.pip_install("pyautogui", version="Latest")
|
|
970
1069
|
import pyautogui
|
|
971
1070
|
except Exception:
|
|
972
1071
|
print("\nPyAutoGUI required! Installing now...")
|
|
973
|
-
shared_utils.pip_install(
|
|
974
|
-
"pyautogui", version=constants.PyAutoGUI.VER
|
|
975
|
-
)
|
|
1072
|
+
shared_utils.pip_install("pyautogui", version="Latest")
|
|
976
1073
|
try:
|
|
977
1074
|
import pyautogui
|
|
978
1075
|
except Exception:
|
|
@@ -989,11 +1086,9 @@ def __install_pyautogui_if_missing():
|
|
|
989
1086
|
xvfb_width = 1366
|
|
990
1087
|
xvfb_height = 768
|
|
991
1088
|
if (
|
|
992
|
-
|
|
993
|
-
and sb_config._xvfb_width
|
|
1089
|
+
getattr(sb_config, "_xvfb_width", None)
|
|
994
1090
|
and isinstance(sb_config._xvfb_width, int)
|
|
995
|
-
and
|
|
996
|
-
and sb_config._xvfb_height
|
|
1091
|
+
and getattr(sb_config, "_xvfb_height", None)
|
|
997
1092
|
and isinstance(sb_config._xvfb_height, int)
|
|
998
1093
|
):
|
|
999
1094
|
xvfb_width = sb_config._xvfb_width
|
|
@@ -1020,8 +1115,7 @@ def __install_pyautogui_if_missing():
|
|
|
1020
1115
|
sb_config._virtual_display = _xvfb_display
|
|
1021
1116
|
sb_config.headless_active = True
|
|
1022
1117
|
if (
|
|
1023
|
-
|
|
1024
|
-
and sb_config.reuse_session
|
|
1118
|
+
getattr(sb_config, "reuse_session", None)
|
|
1025
1119
|
and hasattr(sb_config, "_vd_list")
|
|
1026
1120
|
and isinstance(sb_config._vd_list, list)
|
|
1027
1121
|
):
|
|
@@ -1053,8 +1147,7 @@ def get_configured_pyautogui(pyautogui_copy):
|
|
|
1053
1147
|
and "DISPLAY" in os.environ.keys()
|
|
1054
1148
|
):
|
|
1055
1149
|
if (
|
|
1056
|
-
|
|
1057
|
-
and sb_config._pyautogui_x11_display
|
|
1150
|
+
getattr(sb_config, "_pyautogui_x11_display", None)
|
|
1058
1151
|
and hasattr(pyautogui_copy._pyautogui_x11, "_display")
|
|
1059
1152
|
and (
|
|
1060
1153
|
sb_config._pyautogui_x11_display
|
|
@@ -1077,9 +1170,7 @@ def uc_gui_press_key(driver, key):
|
|
|
1077
1170
|
install_pyautogui_if_missing(driver)
|
|
1078
1171
|
import pyautogui
|
|
1079
1172
|
pyautogui = get_configured_pyautogui(pyautogui)
|
|
1080
|
-
gui_lock =
|
|
1081
|
-
constants.MultiBrowser.PYAUTOGUILOCK
|
|
1082
|
-
)
|
|
1173
|
+
gui_lock = FileLock(constants.MultiBrowser.PYAUTOGUILOCK)
|
|
1083
1174
|
with gui_lock:
|
|
1084
1175
|
pyautogui.press(key)
|
|
1085
1176
|
|
|
@@ -1088,9 +1179,7 @@ def uc_gui_press_keys(driver, keys):
|
|
|
1088
1179
|
install_pyautogui_if_missing(driver)
|
|
1089
1180
|
import pyautogui
|
|
1090
1181
|
pyautogui = get_configured_pyautogui(pyautogui)
|
|
1091
|
-
gui_lock =
|
|
1092
|
-
constants.MultiBrowser.PYAUTOGUILOCK
|
|
1093
|
-
)
|
|
1182
|
+
gui_lock = FileLock(constants.MultiBrowser.PYAUTOGUILOCK)
|
|
1094
1183
|
with gui_lock:
|
|
1095
1184
|
for key in keys:
|
|
1096
1185
|
pyautogui.press(key)
|
|
@@ -1100,9 +1189,7 @@ def uc_gui_write(driver, text):
|
|
|
1100
1189
|
install_pyautogui_if_missing(driver)
|
|
1101
1190
|
import pyautogui
|
|
1102
1191
|
pyautogui = get_configured_pyautogui(pyautogui)
|
|
1103
|
-
gui_lock =
|
|
1104
|
-
constants.MultiBrowser.PYAUTOGUILOCK
|
|
1105
|
-
)
|
|
1192
|
+
gui_lock = FileLock(constants.MultiBrowser.PYAUTOGUILOCK)
|
|
1106
1193
|
with gui_lock:
|
|
1107
1194
|
pyautogui.write(text)
|
|
1108
1195
|
|
|
@@ -1135,9 +1222,7 @@ def _uc_gui_click_x_y(driver, x, y, timeframe=0.25, uc_lock=False):
|
|
|
1135
1222
|
% (x, y, screen_width, screen_height)
|
|
1136
1223
|
)
|
|
1137
1224
|
if uc_lock:
|
|
1138
|
-
gui_lock =
|
|
1139
|
-
constants.MultiBrowser.PYAUTOGUILOCK
|
|
1140
|
-
)
|
|
1225
|
+
gui_lock = FileLock(constants.MultiBrowser.PYAUTOGUILOCK)
|
|
1141
1226
|
with gui_lock: # Prevent issues with multiple processes
|
|
1142
1227
|
pyautogui.moveTo(x, y, timeframe, pyautogui.easeOutQuad)
|
|
1143
1228
|
if timeframe >= 0.25:
|
|
@@ -1156,9 +1241,7 @@ def _uc_gui_click_x_y(driver, x, y, timeframe=0.25, uc_lock=False):
|
|
|
1156
1241
|
|
|
1157
1242
|
|
|
1158
1243
|
def uc_gui_click_x_y(driver, x, y, timeframe=0.25):
|
|
1159
|
-
gui_lock =
|
|
1160
|
-
constants.MultiBrowser.PYAUTOGUILOCK
|
|
1161
|
-
)
|
|
1244
|
+
gui_lock = FileLock(constants.MultiBrowser.PYAUTOGUILOCK)
|
|
1162
1245
|
with gui_lock: # Prevent issues with multiple processes
|
|
1163
1246
|
install_pyautogui_if_missing(driver)
|
|
1164
1247
|
import pyautogui
|
|
@@ -1169,10 +1252,7 @@ def uc_gui_click_x_y(driver, x, y, timeframe=0.25):
|
|
|
1169
1252
|
connected = driver.is_connected()
|
|
1170
1253
|
if (
|
|
1171
1254
|
not connected
|
|
1172
|
-
and (
|
|
1173
|
-
not hasattr(sb_config, "_saved_width_ratio")
|
|
1174
|
-
or not sb_config._saved_width_ratio
|
|
1175
|
-
)
|
|
1255
|
+
and not getattr(sb_config, "_saved_width_ratio", None)
|
|
1176
1256
|
and not __is_cdp_swap_needed(driver)
|
|
1177
1257
|
):
|
|
1178
1258
|
driver.reconnect(0.1)
|
|
@@ -1207,8 +1287,8 @@ def uc_gui_click_x_y(driver, x, y, timeframe=0.25):
|
|
|
1207
1287
|
driver.cdp.minimize()
|
|
1208
1288
|
driver.cdp.set_window_rect(win_x, win_y, width, height)
|
|
1209
1289
|
if IS_WINDOWS:
|
|
1210
|
-
x = x * width_ratio
|
|
1211
|
-
y = y * width_ratio
|
|
1290
|
+
x = x * (width_ratio + 0.03)
|
|
1291
|
+
y = y * (width_ratio - 0.03)
|
|
1212
1292
|
_uc_gui_click_x_y(driver, x, y, timeframe=timeframe, uc_lock=False)
|
|
1213
1293
|
return
|
|
1214
1294
|
with suppress(Exception):
|
|
@@ -1221,9 +1301,14 @@ def uc_gui_click_x_y(driver, x, y, timeframe=0.25):
|
|
|
1221
1301
|
def _on_a_cf_turnstile_page(driver):
|
|
1222
1302
|
source = driver.get_page_source()
|
|
1223
1303
|
if (
|
|
1224
|
-
|
|
1225
|
-
|
|
1304
|
+
(
|
|
1305
|
+
'data-callback="onCaptchaSuccess"' in source
|
|
1306
|
+
and 'title="reCAPTCHA"' not in source
|
|
1307
|
+
and 'id="recaptcha-token"' not in source
|
|
1308
|
+
)
|
|
1309
|
+
or "/challenge-platform/h/b/" in source
|
|
1226
1310
|
or 'id="challenge-widget-' in source
|
|
1311
|
+
or "challenges.cloudf" in source
|
|
1227
1312
|
or "cf-turnstile-" in source
|
|
1228
1313
|
):
|
|
1229
1314
|
return True
|
|
@@ -1248,6 +1333,8 @@ def _uc_gui_click_captcha(
|
|
|
1248
1333
|
ctype=None,
|
|
1249
1334
|
):
|
|
1250
1335
|
cdp_mode_on_at_start = __is_cdp_swap_needed(driver)
|
|
1336
|
+
if cdp_mode_on_at_start:
|
|
1337
|
+
return driver.cdp.gui_click_captcha()
|
|
1251
1338
|
_on_a_captcha_page = None
|
|
1252
1339
|
if ctype == "cf_t":
|
|
1253
1340
|
if not _on_a_cf_turnstile_page(driver):
|
|
@@ -1276,9 +1363,7 @@ def _uc_gui_click_captcha(
|
|
|
1276
1363
|
x = None
|
|
1277
1364
|
y = None
|
|
1278
1365
|
visible_iframe = True
|
|
1279
|
-
gui_lock =
|
|
1280
|
-
constants.MultiBrowser.PYAUTOGUILOCK
|
|
1281
|
-
)
|
|
1366
|
+
gui_lock = FileLock(constants.MultiBrowser.PYAUTOGUILOCK)
|
|
1282
1367
|
with gui_lock: # Prevent issues with multiple processes
|
|
1283
1368
|
needs_switch = False
|
|
1284
1369
|
width_ratio = 1.0
|
|
@@ -1350,31 +1435,27 @@ def _uc_gui_click_captcha(
|
|
|
1350
1435
|
and driver.is_element_present("%s div" % frame)
|
|
1351
1436
|
):
|
|
1352
1437
|
frame = "%s div" % frame
|
|
1353
|
-
elif (
|
|
1354
|
-
driver.is_element_present('[name*="cf-turnstile-"]')
|
|
1355
|
-
and driver.is_element_present("#challenge-form div > div")
|
|
1356
|
-
):
|
|
1438
|
+
elif driver.is_element_present("#challenge-form div > div"):
|
|
1357
1439
|
frame = "#challenge-form div > div"
|
|
1358
1440
|
elif (
|
|
1359
|
-
driver.is_element_present(
|
|
1360
|
-
and driver.is_element_present(
|
|
1441
|
+
driver.is_element_present(
|
|
1361
1442
|
'[style="display: grid;"] div div'
|
|
1362
1443
|
)
|
|
1363
1444
|
):
|
|
1364
1445
|
frame = '[style="display: grid;"] div div'
|
|
1365
1446
|
elif (
|
|
1366
1447
|
driver.is_element_present('[name*="cf-turnstile-"]')
|
|
1367
|
-
and driver.is_element_present(
|
|
1448
|
+
and driver.is_element_present(
|
|
1449
|
+
".spacer + div div:not([class])"
|
|
1450
|
+
)
|
|
1368
1451
|
):
|
|
1369
|
-
frame = '
|
|
1452
|
+
frame = '.spacer + div div:not([class])'
|
|
1370
1453
|
elif (
|
|
1371
|
-
driver.is_element_present(
|
|
1372
|
-
and driver.is_element_present("div.spacer div")
|
|
1454
|
+
driver.is_element_present(".spacer div:not([class])")
|
|
1373
1455
|
):
|
|
1374
|
-
frame = "
|
|
1456
|
+
frame = ".spacer div:not([class])"
|
|
1375
1457
|
elif (
|
|
1376
|
-
driver.is_element_present(
|
|
1377
|
-
and driver.is_element_present(
|
|
1458
|
+
driver.is_element_present(
|
|
1378
1459
|
'[data-testid*="challenge-"] div'
|
|
1379
1460
|
)
|
|
1380
1461
|
):
|
|
@@ -1383,6 +1464,10 @@ def _uc_gui_click_captcha(
|
|
|
1383
1464
|
"div#turnstile-widget div:not([class])"
|
|
1384
1465
|
):
|
|
1385
1466
|
frame = "div#turnstile-widget div:not([class])"
|
|
1467
|
+
elif driver.is_element_present(
|
|
1468
|
+
"ngx-turnstile div:not([class])"
|
|
1469
|
+
):
|
|
1470
|
+
frame = "ngx-turnstile div:not([class])"
|
|
1386
1471
|
elif driver.is_element_present(
|
|
1387
1472
|
'form div:not([class]):has(input[name*="cf-turn"])'
|
|
1388
1473
|
):
|
|
@@ -1403,10 +1488,22 @@ def _uc_gui_click_captcha(
|
|
|
1403
1488
|
frame = ".cf-turnstile-wrapper"
|
|
1404
1489
|
elif driver.is_element_present('[class="cf-turnstile"]'):
|
|
1405
1490
|
frame = '[class="cf-turnstile"]'
|
|
1491
|
+
elif driver.is_element_present(
|
|
1492
|
+
'[id*="turnstile"] div:not([class])'
|
|
1493
|
+
):
|
|
1494
|
+
frame = '[id*="turnstile"] div:not([class])'
|
|
1495
|
+
elif driver.is_element_present(
|
|
1496
|
+
'[class*="turnstile"] div:not([class])'
|
|
1497
|
+
):
|
|
1498
|
+
frame = '[class*="turnstile"] div:not([class])'
|
|
1406
1499
|
elif driver.is_element_present(
|
|
1407
1500
|
'[data-callback="onCaptchaSuccess"]'
|
|
1408
1501
|
):
|
|
1409
1502
|
frame = '[data-callback="onCaptchaSuccess"]'
|
|
1503
|
+
elif driver.is_element_present(
|
|
1504
|
+
"div:not([class]) > div:not([class])"
|
|
1505
|
+
):
|
|
1506
|
+
frame = "div:not([class]) > div:not([class])"
|
|
1410
1507
|
else:
|
|
1411
1508
|
return
|
|
1412
1509
|
if (
|
|
@@ -1454,9 +1551,11 @@ def _uc_gui_click_captcha(
|
|
|
1454
1551
|
else:
|
|
1455
1552
|
driver.execute_script(script)
|
|
1456
1553
|
elif (
|
|
1457
|
-
driver.is_element_present(
|
|
1458
|
-
|
|
1459
|
-
|
|
1554
|
+
driver.is_element_present(
|
|
1555
|
+
'form [id*="turnstile"] div:not([class])'
|
|
1556
|
+
)
|
|
1557
|
+
or driver.is_element_present(
|
|
1558
|
+
'form [class*="turnstile"] div:not([class])'
|
|
1460
1559
|
)
|
|
1461
1560
|
):
|
|
1462
1561
|
script = (
|
|
@@ -1464,12 +1563,35 @@ def _uc_gui_click_captcha(
|
|
|
1464
1563
|
'form [id*="turnstile"]');
|
|
1465
1564
|
var index = 0, length = $elements.length;
|
|
1466
1565
|
for(; index < length; index++){
|
|
1566
|
+
$elements[index].setAttribute('align', 'left');}
|
|
1567
|
+
var $elements = document.querySelectorAll(
|
|
1568
|
+
'form [class*="turnstile"]');
|
|
1569
|
+
var index = 0, length = $elements.length;
|
|
1570
|
+
for(; index < length; index++){
|
|
1467
1571
|
$elements[index].setAttribute('align', 'left');}"""
|
|
1468
1572
|
)
|
|
1469
1573
|
if __is_cdp_swap_needed(driver):
|
|
1470
1574
|
driver.cdp.evaluate(script)
|
|
1471
1575
|
else:
|
|
1472
1576
|
driver.execute_script(script)
|
|
1577
|
+
elif (
|
|
1578
|
+
driver.is_element_present(
|
|
1579
|
+
'[style*="text-align: center;"] div:not([class])'
|
|
1580
|
+
)
|
|
1581
|
+
):
|
|
1582
|
+
script = (
|
|
1583
|
+
"""var $elements = document.querySelectorAll(
|
|
1584
|
+
'[style*="text-align: center;"]');
|
|
1585
|
+
var index = 0, length = $elements.length;
|
|
1586
|
+
for(; index < length; index++){
|
|
1587
|
+
the_style = $elements[index].getAttribute('style');
|
|
1588
|
+
new_style = the_style.replaceAll('center', 'left');
|
|
1589
|
+
$elements[index].setAttribute('style', new_style);}"""
|
|
1590
|
+
)
|
|
1591
|
+
if __is_cdp_swap_needed(driver):
|
|
1592
|
+
driver.cdp.evaluate(script)
|
|
1593
|
+
else:
|
|
1594
|
+
driver.execute_script(script)
|
|
1473
1595
|
if not is_in_frame or needs_switch:
|
|
1474
1596
|
# Currently not in frame (or nested frame outside CF one)
|
|
1475
1597
|
try:
|
|
@@ -1639,9 +1761,7 @@ def _uc_gui_handle_captcha_(driver, frame="iframe", ctype=None):
|
|
|
1639
1761
|
import pyautogui
|
|
1640
1762
|
pyautogui = get_configured_pyautogui(pyautogui)
|
|
1641
1763
|
visible_iframe = True
|
|
1642
|
-
gui_lock =
|
|
1643
|
-
constants.MultiBrowser.PYAUTOGUILOCK
|
|
1644
|
-
)
|
|
1764
|
+
gui_lock = FileLock(constants.MultiBrowser.PYAUTOGUILOCK)
|
|
1645
1765
|
with gui_lock: # Prevent issues with multiple processes
|
|
1646
1766
|
needs_switch = False
|
|
1647
1767
|
if not __is_cdp_swap_needed(driver):
|
|
@@ -1691,9 +1811,9 @@ def _uc_gui_handle_captcha_(driver, frame="iframe", ctype=None):
|
|
|
1691
1811
|
frame = '[data-callback="onCaptchaSuccess"]'
|
|
1692
1812
|
elif (
|
|
1693
1813
|
driver.is_element_present('[name*="cf-turnstile-"]')
|
|
1694
|
-
and driver.is_element_present("
|
|
1814
|
+
and driver.is_element_present(".spacer div:not([class])")
|
|
1695
1815
|
):
|
|
1696
|
-
frame = "
|
|
1816
|
+
frame = ".spacer div:not([class])"
|
|
1697
1817
|
elif (
|
|
1698
1818
|
driver.is_element_present('script[src*="challenges.c"]')
|
|
1699
1819
|
and driver.is_element_present(
|
|
@@ -1727,6 +1847,10 @@ def _uc_gui_handle_captcha_(driver, frame="iframe", ctype=None):
|
|
|
1727
1847
|
frame = ".cf-turnstile-wrapper"
|
|
1728
1848
|
elif driver.is_element_present('[class="cf-turnstile"]'):
|
|
1729
1849
|
frame = '[class="cf-turnstile"]'
|
|
1850
|
+
elif driver.is_element_present(
|
|
1851
|
+
"div:not([class]) > div:not([class])"
|
|
1852
|
+
):
|
|
1853
|
+
frame = "div:not([class]) > div:not([class])"
|
|
1730
1854
|
else:
|
|
1731
1855
|
return
|
|
1732
1856
|
else:
|
|
@@ -1786,8 +1910,7 @@ def _uc_gui_handle_captcha_(driver, frame="iframe", ctype=None):
|
|
|
1786
1910
|
driver.is_element_present(".footer .clearfix .ray-id")
|
|
1787
1911
|
or driver.is_element_present("script[data-cf-beacon]")
|
|
1788
1912
|
)
|
|
1789
|
-
and
|
|
1790
|
-
and sb_config._saved_cf_tab_count
|
|
1913
|
+
and getattr(sb_config, "_saved_cf_tab_count", None)
|
|
1791
1914
|
and not __is_cdp_swap_needed(driver)
|
|
1792
1915
|
):
|
|
1793
1916
|
driver.uc_open_with_disconnect(driver.current_url, 3.8)
|
|
@@ -1903,6 +2026,15 @@ def get_valid_binary_names_for_browser(browser):
|
|
|
1903
2026
|
raise Exception("Invalid combination for OS browser binaries!")
|
|
1904
2027
|
|
|
1905
2028
|
|
|
2029
|
+
def _special_binary_exists(location, name):
|
|
2030
|
+
filename = str(location).split("/")[-1].split("\\")[-1]
|
|
2031
|
+
return (
|
|
2032
|
+
location
|
|
2033
|
+
and str(name).lower() in filename.lower()
|
|
2034
|
+
and os.path.exists(location)
|
|
2035
|
+
)
|
|
2036
|
+
|
|
2037
|
+
|
|
1906
2038
|
def _repair_chromedriver(chrome_options, headless_options, mcv=None):
|
|
1907
2039
|
if mcv:
|
|
1908
2040
|
subprocess.check_call(
|
|
@@ -1957,14 +2089,12 @@ def _repair_edgedriver(edge_version):
|
|
|
1957
2089
|
|
|
1958
2090
|
|
|
1959
2091
|
def _mark_driver_repaired():
|
|
1960
|
-
import codecs
|
|
1961
|
-
|
|
1962
2092
|
abs_path = os.path.abspath(".")
|
|
1963
2093
|
driver_repaired_lock = constants.MultiBrowser.DRIVER_REPAIRED
|
|
1964
2094
|
file_path = os.path.join(abs_path, driver_repaired_lock)
|
|
1965
2095
|
if not os.path.exists(DOWNLOADS_FOLDER):
|
|
1966
2096
|
os.makedirs(DOWNLOADS_FOLDER)
|
|
1967
|
-
out_file =
|
|
2097
|
+
out_file = open(file_path, mode="w+", encoding="utf-8")
|
|
1968
2098
|
out_file.writelines("")
|
|
1969
2099
|
out_file.close()
|
|
1970
2100
|
|
|
@@ -2006,6 +2136,7 @@ def _add_chrome_proxy_extension(
|
|
|
2006
2136
|
"""Implementation of https://stackoverflow.com/a/35293284/7058266
|
|
2007
2137
|
for https://stackoverflow.com/q/12848327/7058266
|
|
2008
2138
|
(Run Selenium on a proxy server that requires authentication.)"""
|
|
2139
|
+
zip_it = False
|
|
2009
2140
|
args = " ".join(sys.argv)
|
|
2010
2141
|
bypass_list = proxy_bypass_list
|
|
2011
2142
|
if (
|
|
@@ -2349,6 +2480,19 @@ def _set_chrome_options(
|
|
|
2349
2480
|
and not recorder_ext
|
|
2350
2481
|
and (not extension_zip and not extension_dir)
|
|
2351
2482
|
):
|
|
2483
|
+
if (
|
|
2484
|
+
binary_location
|
|
2485
|
+
and isinstance(binary_location, str)
|
|
2486
|
+
and (
|
|
2487
|
+
binary_location.lower().endswith("comet")
|
|
2488
|
+
or binary_location.lower().endswith("comet.exe")
|
|
2489
|
+
or binary_location.lower().endswith("atlas")
|
|
2490
|
+
or binary_location.lower().endswith("atlas.exe")
|
|
2491
|
+
)
|
|
2492
|
+
):
|
|
2493
|
+
# AI browsers don't like Incognito / Guest Mode
|
|
2494
|
+
incognito = False
|
|
2495
|
+
guest_mode = False
|
|
2352
2496
|
if incognito:
|
|
2353
2497
|
# Use Chrome's Incognito Mode
|
|
2354
2498
|
# Incognito Mode prevents Chrome extensions from loading,
|
|
@@ -2372,14 +2516,28 @@ def _set_chrome_options(
|
|
|
2372
2516
|
# Can be a comma-separated list of .ZIP or .CRX files
|
|
2373
2517
|
extension_zip_list = extension_zip.split(",")
|
|
2374
2518
|
for extension_zip_item in extension_zip_list:
|
|
2375
|
-
abs_path = os.path.
|
|
2376
|
-
|
|
2519
|
+
abs_path = os.path.realpath(extension_zip_item)
|
|
2520
|
+
if os.path.exists(abs_path):
|
|
2521
|
+
try:
|
|
2522
|
+
abs_path_dir = os.path.join(
|
|
2523
|
+
DOWNLOADS_FOLDER, abs_path.split(".")[0]
|
|
2524
|
+
)
|
|
2525
|
+
_unzip_to_new_folder(abs_path, abs_path_dir)
|
|
2526
|
+
chrome_options = add_chrome_ext_dir(
|
|
2527
|
+
chrome_options, abs_path_dir
|
|
2528
|
+
)
|
|
2529
|
+
sb_config._ext_dirs.append(abs_path_dir)
|
|
2530
|
+
except Exception:
|
|
2531
|
+
with suppress(Exception):
|
|
2532
|
+
chrome_options.add_extension(abs_path)
|
|
2377
2533
|
if extension_dir:
|
|
2378
2534
|
# load-extension input can be a comma-separated list
|
|
2379
2535
|
abs_path = (
|
|
2380
|
-
",".join(os.path.
|
|
2536
|
+
",".join(os.path.realpath(p) for p in extension_dir.split(","))
|
|
2381
2537
|
)
|
|
2382
2538
|
chrome_options = add_chrome_ext_dir(chrome_options, abs_path)
|
|
2539
|
+
for p in extension_dir.split(","):
|
|
2540
|
+
sb_config._ext_dirs.append(os.path.realpath(p))
|
|
2383
2541
|
if (
|
|
2384
2542
|
page_load_strategy
|
|
2385
2543
|
and page_load_strategy.lower() in ["eager", "none"]
|
|
@@ -2388,8 +2546,7 @@ def _set_chrome_options(
|
|
|
2388
2546
|
chrome_options.page_load_strategy = page_load_strategy.lower()
|
|
2389
2547
|
elif (
|
|
2390
2548
|
not page_load_strategy
|
|
2391
|
-
and
|
|
2392
|
-
and settings.PAGE_LOAD_STRATEGY
|
|
2549
|
+
and getattr(settings, "PAGE_LOAD_STRATEGY", None)
|
|
2393
2550
|
and settings.PAGE_LOAD_STRATEGY.lower() in ["eager", "none"]
|
|
2394
2551
|
):
|
|
2395
2552
|
# Only change it if not "normal", which is the default.
|
|
@@ -2414,37 +2571,32 @@ def _set_chrome_options(
|
|
|
2414
2571
|
if (settings.DISABLE_CSP_ON_CHROME or disable_csp) and not headless:
|
|
2415
2572
|
# Headless Chrome does not support extensions, which are required
|
|
2416
2573
|
# for disabling the Content Security Policy on Chrome.
|
|
2417
|
-
|
|
2418
|
-
|
|
2419
|
-
|
|
2420
|
-
|
|
2421
|
-
chrome_options
|
|
2422
|
-
|
|
2423
|
-
|
|
2424
|
-
else:
|
|
2425
|
-
chrome_options = _add_chrome_disable_csp_extension(chrome_options)
|
|
2574
|
+
disable_csp_zip = DISABLE_CSP_ZIP_PATH
|
|
2575
|
+
disable_csp_dir = os.path.join(DOWNLOADS_FOLDER, "disable_csp")
|
|
2576
|
+
_unzip_to_new_folder(disable_csp_zip, disable_csp_dir)
|
|
2577
|
+
chrome_options = add_chrome_ext_dir(
|
|
2578
|
+
chrome_options, disable_csp_dir
|
|
2579
|
+
)
|
|
2580
|
+
sb_config._ext_dirs.append(disable_csp_dir)
|
|
2426
2581
|
if ad_block_on and not headless:
|
|
2427
2582
|
# Headless Chrome does not support extensions.
|
|
2428
|
-
|
|
2429
|
-
|
|
2430
|
-
|
|
2431
|
-
|
|
2432
|
-
|
|
2433
|
-
else:
|
|
2434
|
-
chrome_options = _add_chrome_ad_block_extension(chrome_options)
|
|
2583
|
+
ad_block_zip = AD_BLOCK_ZIP_PATH
|
|
2584
|
+
ad_block_dir = os.path.join(DOWNLOADS_FOLDER, "ad_block")
|
|
2585
|
+
_unzip_to_new_folder(ad_block_zip, ad_block_dir)
|
|
2586
|
+
chrome_options = add_chrome_ext_dir(chrome_options, ad_block_dir)
|
|
2587
|
+
sb_config._ext_dirs.append(ad_block_dir)
|
|
2435
2588
|
if recorder_ext and not headless:
|
|
2436
|
-
|
|
2437
|
-
|
|
2438
|
-
|
|
2439
|
-
|
|
2440
|
-
|
|
2441
|
-
else:
|
|
2442
|
-
chrome_options = _add_chrome_recorder_extension(chrome_options)
|
|
2589
|
+
recorder_zip = RECORDER_ZIP_PATH
|
|
2590
|
+
recorder_dir = os.path.join(DOWNLOADS_FOLDER, "recorder")
|
|
2591
|
+
_unzip_to_new_folder(recorder_zip, recorder_dir)
|
|
2592
|
+
chrome_options = add_chrome_ext_dir(chrome_options, recorder_dir)
|
|
2593
|
+
sb_config._ext_dirs.append(recorder_dir)
|
|
2443
2594
|
if chromium_arg and "sbase" in chromium_arg:
|
|
2444
2595
|
sbase_ext_zip = SBASE_EXT_ZIP_PATH
|
|
2445
2596
|
sbase_ext_dir = os.path.join(DOWNLOADS_FOLDER, "sbase_ext")
|
|
2446
2597
|
_unzip_to_new_folder(sbase_ext_zip, sbase_ext_dir)
|
|
2447
2598
|
chrome_options = add_chrome_ext_dir(chrome_options, sbase_ext_dir)
|
|
2599
|
+
sb_config._ext_dirs.append(sbase_ext_dir)
|
|
2448
2600
|
if proxy_string:
|
|
2449
2601
|
if proxy_auth:
|
|
2450
2602
|
zip_it = True
|
|
@@ -2527,15 +2679,20 @@ def _set_chrome_options(
|
|
|
2527
2679
|
if is_using_uc(undetectable, browser_name):
|
|
2528
2680
|
chrome_options.add_argument("--disable-application-cache")
|
|
2529
2681
|
chrome_options.add_argument("--disable-setuid-sandbox")
|
|
2530
|
-
|
|
2682
|
+
if not binary_location:
|
|
2683
|
+
if os.path.exists("/bin/google-chrome"):
|
|
2684
|
+
binary_location = "/bin/google-chrome"
|
|
2685
|
+
elif os.path.exists("/usr/bin/google-chrome-stable"):
|
|
2686
|
+
binary_location = "/usr/bin/google-chrome-stable"
|
|
2687
|
+
elif os.path.exists("/usr/bin/google-chrome"):
|
|
2688
|
+
binary_location = "/usr/bin/google-chrome"
|
|
2689
|
+
elif os.path.exists("/usr/bin/google-chrome-stable"):
|
|
2690
|
+
binary_location = "/usr/bin/google-chrome-stable"
|
|
2691
|
+
else:
|
|
2531
2692
|
br_app = "google-chrome"
|
|
2532
2693
|
binary_loc = detect_b_ver.get_binary_location(br_app, True)
|
|
2533
2694
|
if os.path.exists(binary_loc):
|
|
2534
2695
|
binary_location = binary_loc
|
|
2535
|
-
elif os.path.exists("/usr/bin/google-chrome-stable"):
|
|
2536
|
-
binary_location = "/usr/bin/google-chrome-stable"
|
|
2537
|
-
elif os.path.exists("/usr/bin/google-chrome"):
|
|
2538
|
-
binary_location = "/usr/bin/google-chrome"
|
|
2539
2696
|
extra_disabled_features = []
|
|
2540
2697
|
if chromium_arg:
|
|
2541
2698
|
# Can be a comma-separated list of Chromium args or a list
|
|
@@ -2592,6 +2749,7 @@ def _set_chrome_options(
|
|
|
2592
2749
|
chrome_options.add_argument("--disable-renderer-backgrounding")
|
|
2593
2750
|
chrome_options.add_argument("--disable-backgrounding-occluded-windows")
|
|
2594
2751
|
chrome_options.add_argument("--disable-client-side-phishing-detection")
|
|
2752
|
+
chrome_options.add_argument("--disable-device-discovery-notifications")
|
|
2595
2753
|
chrome_options.add_argument("--disable-oopr-debug-crash-dump")
|
|
2596
2754
|
chrome_options.add_argument("--disable-top-sites")
|
|
2597
2755
|
chrome_options.add_argument("--ash-no-nudges")
|
|
@@ -2608,6 +2766,7 @@ def _set_chrome_options(
|
|
|
2608
2766
|
included_disabled_features.append("OptimizationHints")
|
|
2609
2767
|
included_disabled_features.append("OptimizationHintsFetching")
|
|
2610
2768
|
included_disabled_features.append("Translate")
|
|
2769
|
+
included_disabled_features.append("ComponentUpdater")
|
|
2611
2770
|
included_disabled_features.append("OptimizationTargetPrediction")
|
|
2612
2771
|
included_disabled_features.append("OptimizationGuideModelDownloading")
|
|
2613
2772
|
included_disabled_features.append("DownloadBubble")
|
|
@@ -2618,11 +2777,24 @@ def _set_chrome_options(
|
|
|
2618
2777
|
included_disabled_features.append("SidePanelPinning")
|
|
2619
2778
|
included_disabled_features.append("UserAgentClientHint")
|
|
2620
2779
|
included_disabled_features.append("DisableLoadExtensionCommandLineSwitch")
|
|
2780
|
+
included_disabled_features.append("Bluetooth")
|
|
2781
|
+
included_disabled_features.append("WebBluetooth")
|
|
2782
|
+
included_disabled_features.append("UnifiedWebBluetooth")
|
|
2783
|
+
included_disabled_features.append("WebAuthentication")
|
|
2784
|
+
included_disabled_features.append("PasskeyAuth")
|
|
2621
2785
|
for item in extra_disabled_features:
|
|
2622
2786
|
if item not in included_disabled_features:
|
|
2623
2787
|
included_disabled_features.append(item)
|
|
2624
2788
|
d_f_string = ",".join(included_disabled_features)
|
|
2625
2789
|
chrome_options.add_argument("--disable-features=%s" % d_f_string)
|
|
2790
|
+
chrome_options.add_argument("--enable-unsafe-extension-debugging")
|
|
2791
|
+
if proxy_string:
|
|
2792
|
+
chrome_options.add_argument("--test-type")
|
|
2793
|
+
if proxy_auth or sb_config._ext_dirs:
|
|
2794
|
+
if not is_using_uc(undetectable, browser_name):
|
|
2795
|
+
chrome_options.add_argument("--remote-debugging-pipe")
|
|
2796
|
+
chrome_options.enable_webextensions = True
|
|
2797
|
+
chrome_options.enable_bidi = True
|
|
2626
2798
|
if (
|
|
2627
2799
|
is_using_uc(undetectable, browser_name)
|
|
2628
2800
|
and (
|
|
@@ -2640,7 +2812,8 @@ def _set_chrome_options(
|
|
|
2640
2812
|
chrome_options.add_argument("--disable-popup-blocking")
|
|
2641
2813
|
# Skip remaining options that trigger anti-bot services
|
|
2642
2814
|
return chrome_options
|
|
2643
|
-
|
|
2815
|
+
if not proxy_string:
|
|
2816
|
+
chrome_options.add_argument("--test-type")
|
|
2644
2817
|
chrome_options.add_argument("--log-level=3")
|
|
2645
2818
|
chrome_options.add_argument("--no-first-run")
|
|
2646
2819
|
chrome_options.add_argument("--allow-insecure-localhost")
|
|
@@ -2886,21 +3059,29 @@ def get_driver(
|
|
|
2886
3059
|
device_pixel_ratio=None,
|
|
2887
3060
|
browser=None, # A duplicate of browser_name to avoid confusion
|
|
2888
3061
|
):
|
|
3062
|
+
sb_config._ext_dirs = []
|
|
2889
3063
|
driver_dir = DRIVER_DIR
|
|
2890
|
-
if
|
|
2891
|
-
|
|
2892
|
-
|
|
2893
|
-
):
|
|
3064
|
+
if binary_location == "_chromium_":
|
|
3065
|
+
driver_dir = DRIVER_DIR_CHROMIUM
|
|
3066
|
+
elif binary_location == "cft":
|
|
2894
3067
|
driver_dir = DRIVER_DIR_CFT
|
|
2895
|
-
|
|
2896
|
-
hasattr(sb_config, "binary_location")
|
|
2897
|
-
and sb_config.binary_location == "chs"
|
|
2898
|
-
):
|
|
3068
|
+
elif binary_location == "chs":
|
|
2899
3069
|
driver_dir = DRIVER_DIR_CHS
|
|
3070
|
+
elif _special_binary_exists(binary_location, "opera"):
|
|
3071
|
+
driver_dir = DRIVER_DIR_OPERA
|
|
3072
|
+
sb_config._cdp_browser = "opera"
|
|
3073
|
+
elif _special_binary_exists(binary_location, "brave"):
|
|
3074
|
+
driver_dir = DRIVER_DIR_BRAVE
|
|
3075
|
+
sb_config._cdp_browser = "brave"
|
|
3076
|
+
elif _special_binary_exists(binary_location, "comet"):
|
|
3077
|
+
driver_dir = DRIVER_DIR_COMET
|
|
3078
|
+
sb_config._cdp_browser = "comet"
|
|
3079
|
+
elif _special_binary_exists(binary_location, "atlas"):
|
|
3080
|
+
driver_dir = DRIVER_DIR_ATLAS
|
|
3081
|
+
sb_config._cdp_browser = "atlas"
|
|
2900
3082
|
if (
|
|
2901
3083
|
hasattr(sb_config, "settings")
|
|
2902
|
-
and
|
|
2903
|
-
and sb_config.settings.NEW_DRIVER_DIR
|
|
3084
|
+
and getattr(sb_config.settings, "NEW_DRIVER_DIR", None)
|
|
2904
3085
|
and os.path.exists(sb_config.settings.NEW_DRIVER_DIR)
|
|
2905
3086
|
):
|
|
2906
3087
|
driver_dir = sb_config.settings.NEW_DRIVER_DIR
|
|
@@ -2909,7 +3090,26 @@ def get_driver(
|
|
|
2909
3090
|
browser_name = browser
|
|
2910
3091
|
else:
|
|
2911
3092
|
browser_name = "chrome" # The default if not specified
|
|
3093
|
+
if browser_name in constants.ChromiumSubs.chromium_subs:
|
|
3094
|
+
browser_name = "chrome"
|
|
2912
3095
|
browser_name = browser_name.lower()
|
|
3096
|
+
if is_using_uc(undetectable, browser_name):
|
|
3097
|
+
if ad_block_on:
|
|
3098
|
+
sb_config.ad_block_on = True
|
|
3099
|
+
else:
|
|
3100
|
+
sb_config.ad_block_on = False
|
|
3101
|
+
if disable_csp:
|
|
3102
|
+
sb_config.disable_csp = True
|
|
3103
|
+
else:
|
|
3104
|
+
sb_config.disable_csp = False
|
|
3105
|
+
if mobile_emulator:
|
|
3106
|
+
# For stealthy mobile mode, see the CDP Mode examples
|
|
3107
|
+
# to learn how to properly configure it.
|
|
3108
|
+
user_agent = None # Undo the override
|
|
3109
|
+
mobile_emulator = False # Instead, set from CDP Mode
|
|
3110
|
+
sb_config._cdp_mobile_mode = True
|
|
3111
|
+
else:
|
|
3112
|
+
sb_config._cdp_mobile_mode = False
|
|
2913
3113
|
if headless2 and browser_name == constants.Browser.FIREFOX:
|
|
2914
3114
|
headless2 = False # Only for Chromium
|
|
2915
3115
|
headless = True
|
|
@@ -2930,6 +3130,51 @@ def get_driver(
|
|
|
2930
3130
|
or browser_name == constants.Browser.EDGE
|
|
2931
3131
|
)
|
|
2932
3132
|
):
|
|
3133
|
+
if (
|
|
3134
|
+
binary_location.lower() == "_chromium_"
|
|
3135
|
+
and browser_name == constants.Browser.GOOGLE_CHROME
|
|
3136
|
+
):
|
|
3137
|
+
binary_folder = None
|
|
3138
|
+
if IS_MAC:
|
|
3139
|
+
binary_folder = "chrome-mac"
|
|
3140
|
+
elif IS_LINUX:
|
|
3141
|
+
binary_folder = "chrome-linux"
|
|
3142
|
+
elif IS_WINDOWS:
|
|
3143
|
+
binary_folder = "chrome-win"
|
|
3144
|
+
if binary_folder:
|
|
3145
|
+
binary_location = os.path.join(driver_dir, binary_folder)
|
|
3146
|
+
if not os.path.exists(binary_location):
|
|
3147
|
+
from seleniumbase.console_scripts import sb_install
|
|
3148
|
+
args = " ".join(sys.argv)
|
|
3149
|
+
if not (
|
|
3150
|
+
"-n" in sys.argv or " -n=" in args or args == "-c"
|
|
3151
|
+
):
|
|
3152
|
+
# (Not multithreaded)
|
|
3153
|
+
sys_args = sys.argv # Save a copy of current sys args
|
|
3154
|
+
log_d("\nWarning: Chromium binary not found...")
|
|
3155
|
+
try:
|
|
3156
|
+
sb_install.main(override="chromium")
|
|
3157
|
+
except Exception as e:
|
|
3158
|
+
log_d("\nWarning: Chrome download failed: %s" % e)
|
|
3159
|
+
sys.argv = sys_args # Put back the original sys args
|
|
3160
|
+
else:
|
|
3161
|
+
chrome_fixing_lock = fasteners.InterProcessLock(
|
|
3162
|
+
constants.MultiBrowser.DRIVER_FIXING_LOCK
|
|
3163
|
+
)
|
|
3164
|
+
with chrome_fixing_lock:
|
|
3165
|
+
with suppress(Exception):
|
|
3166
|
+
shared_utils.make_writable(
|
|
3167
|
+
constants.MultiBrowser.DRIVER_FIXING_LOCK
|
|
3168
|
+
)
|
|
3169
|
+
if not os.path.exists(binary_location):
|
|
3170
|
+
sys_args = sys.argv # Save a copy of sys args
|
|
3171
|
+
log_d(
|
|
3172
|
+
"\nWarning: Chromium binary not found..."
|
|
3173
|
+
)
|
|
3174
|
+
sb_install.main(override="chromium")
|
|
3175
|
+
sys.argv = sys_args # Put back original args
|
|
3176
|
+
else:
|
|
3177
|
+
binary_location = None
|
|
2933
3178
|
if (
|
|
2934
3179
|
binary_location.lower() == "cft"
|
|
2935
3180
|
and browser_name == constants.Browser.GOOGLE_CHROME
|
|
@@ -3067,12 +3312,25 @@ def get_driver(
|
|
|
3067
3312
|
binary_name = "Google Chrome for Testing"
|
|
3068
3313
|
binary_location += "/Google Chrome for Testing.app"
|
|
3069
3314
|
binary_location += "/Contents/MacOS/Google Chrome for Testing"
|
|
3315
|
+
elif binary_name == "Chromium.app":
|
|
3316
|
+
binary_name = "Chromium"
|
|
3317
|
+
binary_location += "/Contents/MacOS/Chromium"
|
|
3318
|
+
elif binary_name in ["chrome-mac"]:
|
|
3319
|
+
binary_name = "Chromium"
|
|
3320
|
+
binary_location += "/Chromium.app"
|
|
3321
|
+
binary_location += "/Contents/MacOS/Chromium"
|
|
3070
3322
|
elif binary_name == "chrome-linux64":
|
|
3071
3323
|
binary_name = "chrome"
|
|
3072
3324
|
binary_location += "/chrome"
|
|
3325
|
+
elif binary_name == "chrome-linux":
|
|
3326
|
+
binary_name = "chrome"
|
|
3327
|
+
binary_location += "/chrome"
|
|
3073
3328
|
elif binary_name in ["chrome-win32", "chrome-win64"]:
|
|
3074
3329
|
binary_name = "chrome.exe"
|
|
3075
3330
|
binary_location += "\\chrome.exe"
|
|
3331
|
+
elif binary_name in ["chrome-win"]:
|
|
3332
|
+
binary_name = "chrome.exe"
|
|
3333
|
+
binary_location += "\\chrome.exe"
|
|
3076
3334
|
elif binary_name in [
|
|
3077
3335
|
"chrome-headless-shell-mac-arm64",
|
|
3078
3336
|
"chrome-headless-shell-mac-x64",
|
|
@@ -3110,8 +3368,8 @@ def get_driver(
|
|
|
3110
3368
|
proxy_pass = None
|
|
3111
3369
|
proxy_scheme = "http"
|
|
3112
3370
|
if proxy_string:
|
|
3113
|
-
# (The
|
|
3114
|
-
|
|
3371
|
+
# (The line below is for the Chrome 142 proxy auth fix)
|
|
3372
|
+
sb_config._cdp_proxy = proxy_string
|
|
3115
3373
|
username_and_password = None
|
|
3116
3374
|
if "@" in proxy_string:
|
|
3117
3375
|
# Format => username:password@hostname:port
|
|
@@ -3844,22 +4102,34 @@ def get_local_driver(
|
|
|
3844
4102
|
downloads_path = DOWNLOADS_FOLDER
|
|
3845
4103
|
driver_dir = DRIVER_DIR
|
|
3846
4104
|
special_chrome = False
|
|
3847
|
-
if
|
|
3848
|
-
|
|
3849
|
-
|
|
3850
|
-
|
|
3851
|
-
|
|
3852
|
-
|
|
3853
|
-
|
|
3854
|
-
|
|
3855
|
-
|
|
3856
|
-
|
|
3857
|
-
|
|
3858
|
-
|
|
4105
|
+
if binary_location:
|
|
4106
|
+
if (
|
|
4107
|
+
binary_location == "_chromium_"
|
|
4108
|
+
or "chromium_drivers" in binary_location
|
|
4109
|
+
):
|
|
4110
|
+
special_chrome = True
|
|
4111
|
+
driver_dir = DRIVER_DIR_CHROMIUM
|
|
4112
|
+
elif binary_location == "cft" or "cft_drivers" in binary_location:
|
|
4113
|
+
special_chrome = True
|
|
4114
|
+
driver_dir = DRIVER_DIR_CFT
|
|
4115
|
+
elif binary_location == "chs" or "chs_drivers" in binary_location:
|
|
4116
|
+
special_chrome = True
|
|
4117
|
+
driver_dir = DRIVER_DIR_CHS
|
|
4118
|
+
elif _special_binary_exists(binary_location, "opera"):
|
|
4119
|
+
special_chrome = True
|
|
4120
|
+
driver_dir = DRIVER_DIR_OPERA
|
|
4121
|
+
elif _special_binary_exists(binary_location, "brave"):
|
|
4122
|
+
special_chrome = True
|
|
4123
|
+
driver_dir = DRIVER_DIR_BRAVE
|
|
4124
|
+
elif _special_binary_exists(binary_location, "comet"):
|
|
4125
|
+
special_chrome = True
|
|
4126
|
+
driver_dir = DRIVER_DIR_COMET
|
|
4127
|
+
elif _special_binary_exists(binary_location, "atlas"):
|
|
4128
|
+
special_chrome = True
|
|
4129
|
+
driver_dir = DRIVER_DIR_ATLAS
|
|
3859
4130
|
if (
|
|
3860
4131
|
hasattr(sb_config, "settings")
|
|
3861
|
-
and
|
|
3862
|
-
and sb_config.settings.NEW_DRIVER_DIR
|
|
4132
|
+
and getattr(sb_config.settings, "NEW_DRIVER_DIR", None)
|
|
3863
4133
|
and os.path.exists(sb_config.settings.NEW_DRIVER_DIR)
|
|
3864
4134
|
):
|
|
3865
4135
|
driver_dir = sb_config.settings.NEW_DRIVER_DIR
|
|
@@ -4269,8 +4539,8 @@ def get_local_driver(
|
|
|
4269
4539
|
sys.argv = sys_args # Put back the original sys args
|
|
4270
4540
|
|
|
4271
4541
|
# For Microsoft Edge (Chromium) version 80 or higher
|
|
4272
|
-
Edge = webdriver.
|
|
4273
|
-
EdgeOptions = webdriver.
|
|
4542
|
+
Edge = webdriver.Edge
|
|
4543
|
+
EdgeOptions = webdriver.EdgeOptions
|
|
4274
4544
|
if local_edgedriver and os.path.exists(local_edgedriver):
|
|
4275
4545
|
try:
|
|
4276
4546
|
make_driver_executable_if_not(local_edgedriver)
|
|
@@ -4424,12 +4694,12 @@ def get_local_driver(
|
|
|
4424
4694
|
# Can be a comma-separated list of .ZIP or .CRX files
|
|
4425
4695
|
extension_zip_list = extension_zip.split(",")
|
|
4426
4696
|
for extension_zip_item in extension_zip_list:
|
|
4427
|
-
abs_path = os.path.
|
|
4697
|
+
abs_path = os.path.realpath(extension_zip_item)
|
|
4428
4698
|
edge_options.add_extension(abs_path)
|
|
4429
4699
|
if extension_dir:
|
|
4430
4700
|
# load-extension input can be a comma-separated list
|
|
4431
4701
|
abs_path = (
|
|
4432
|
-
",".join(os.path.
|
|
4702
|
+
",".join(os.path.realpath(p) for p in extension_dir.split(","))
|
|
4433
4703
|
)
|
|
4434
4704
|
edge_options = add_chrome_ext_dir(edge_options, abs_path)
|
|
4435
4705
|
edge_options.add_argument("--disable-infobars")
|
|
@@ -4469,8 +4739,7 @@ def get_local_driver(
|
|
|
4469
4739
|
edge_options.page_load_strategy = page_load_strategy.lower()
|
|
4470
4740
|
elif (
|
|
4471
4741
|
not page_load_strategy
|
|
4472
|
-
and
|
|
4473
|
-
and settings.PAGE_LOAD_STRATEGY
|
|
4742
|
+
and getattr(settings, "PAGE_LOAD_STRATEGY", None)
|
|
4474
4743
|
and settings.PAGE_LOAD_STRATEGY.lower() in ["eager", "none"]
|
|
4475
4744
|
):
|
|
4476
4745
|
# Only change it if not "normal", which is the default.
|
|
@@ -4581,6 +4850,7 @@ def get_local_driver(
|
|
|
4581
4850
|
included_disabled_features.append("OptimizationHints")
|
|
4582
4851
|
included_disabled_features.append("OptimizationHintsFetching")
|
|
4583
4852
|
included_disabled_features.append("Translate")
|
|
4853
|
+
included_disabled_features.append("ComponentUpdater")
|
|
4584
4854
|
included_disabled_features.append("OptimizationTargetPrediction")
|
|
4585
4855
|
included_disabled_features.append("OptimizationGuideModelDownloading")
|
|
4586
4856
|
included_disabled_features.append("InsecureDownloadWarnings")
|
|
@@ -4591,6 +4861,11 @@ def get_local_driver(
|
|
|
4591
4861
|
included_disabled_features.append(
|
|
4592
4862
|
"DisableLoadExtensionCommandLineSwitch"
|
|
4593
4863
|
)
|
|
4864
|
+
included_disabled_features.append("Bluetooth")
|
|
4865
|
+
included_disabled_features.append("WebBluetooth")
|
|
4866
|
+
included_disabled_features.append("UnifiedWebBluetooth")
|
|
4867
|
+
included_disabled_features.append("WebAuthentication")
|
|
4868
|
+
included_disabled_features.append("PasskeyAuth")
|
|
4594
4869
|
for item in extra_disabled_features:
|
|
4595
4870
|
if item not in included_disabled_features:
|
|
4596
4871
|
included_disabled_features.append(item)
|
|
@@ -4682,8 +4957,7 @@ def get_local_driver(
|
|
|
4682
4957
|
options.page_load_strategy = page_load_strategy.lower()
|
|
4683
4958
|
elif (
|
|
4684
4959
|
not page_load_strategy
|
|
4685
|
-
and
|
|
4686
|
-
and settings.PAGE_LOAD_STRATEGY
|
|
4960
|
+
and getattr(settings, "PAGE_LOAD_STRATEGY", None)
|
|
4687
4961
|
and settings.PAGE_LOAD_STRATEGY.lower() in ["eager", "none"]
|
|
4688
4962
|
):
|
|
4689
4963
|
# Only change it if not "normal", which is the default.
|
|
@@ -4693,6 +4967,27 @@ def get_local_driver(
|
|
|
4693
4967
|
)
|
|
4694
4968
|
return extend_driver(driver)
|
|
4695
4969
|
elif browser_name == constants.Browser.GOOGLE_CHROME:
|
|
4970
|
+
set_chromium = None
|
|
4971
|
+
if _special_binary_exists(binary_location, "opera"):
|
|
4972
|
+
set_chromium = "opera"
|
|
4973
|
+
local_chromedriver = DRIVER_DIR_OPERA + "/chromedriver"
|
|
4974
|
+
if IS_WINDOWS:
|
|
4975
|
+
local_chromedriver = DRIVER_DIR_OPERA + "/chromedriver.exe"
|
|
4976
|
+
if _special_binary_exists(binary_location, "brave"):
|
|
4977
|
+
set_chromium = "brave"
|
|
4978
|
+
local_chromedriver = DRIVER_DIR_BRAVE + "/chromedriver"
|
|
4979
|
+
if IS_WINDOWS:
|
|
4980
|
+
local_chromedriver = DRIVER_DIR_BRAVE + "/chromedriver.exe"
|
|
4981
|
+
if _special_binary_exists(binary_location, "comet"):
|
|
4982
|
+
set_chromium = "comet"
|
|
4983
|
+
local_chromedriver = DRIVER_DIR_COMET + "/chromedriver"
|
|
4984
|
+
if IS_WINDOWS:
|
|
4985
|
+
local_chromedriver = DRIVER_DIR_COMET + "/chromedriver.exe"
|
|
4986
|
+
if _special_binary_exists(binary_location, "atlas"):
|
|
4987
|
+
set_chromium = "atlas"
|
|
4988
|
+
local_chromedriver = DRIVER_DIR_ATLAS + "/chromedriver"
|
|
4989
|
+
if IS_WINDOWS:
|
|
4990
|
+
local_chromedriver = DRIVER_DIR_ATLAS + "/chromedriver.exe"
|
|
4696
4991
|
try:
|
|
4697
4992
|
chrome_options = _set_chrome_options(
|
|
4698
4993
|
browser_name,
|
|
@@ -4750,6 +5045,8 @@ def get_local_driver(
|
|
|
4750
5045
|
device_height,
|
|
4751
5046
|
device_pixel_ratio,
|
|
4752
5047
|
)
|
|
5048
|
+
if binary_location and "chromium_drivers" in binary_location:
|
|
5049
|
+
chrome_options.add_argument("--use-mock-keychain")
|
|
4753
5050
|
use_version = "latest"
|
|
4754
5051
|
major_chrome_version = None
|
|
4755
5052
|
saved_mcv = None
|
|
@@ -4814,6 +5111,12 @@ def get_local_driver(
|
|
|
4814
5111
|
major_chrome_version = None
|
|
4815
5112
|
if major_chrome_version:
|
|
4816
5113
|
use_version = major_chrome_version
|
|
5114
|
+
if (
|
|
5115
|
+
set_chromium == "opera"
|
|
5116
|
+
and use_version.isnumeric()
|
|
5117
|
+
and int(use_version) < 130
|
|
5118
|
+
):
|
|
5119
|
+
use_version = "130" # Special case
|
|
4817
5120
|
ch_driver_version = None
|
|
4818
5121
|
path_chromedriver = chromedriver_on_path()
|
|
4819
5122
|
if os.path.exists(local_chromedriver):
|
|
@@ -4831,7 +5134,7 @@ def get_local_driver(
|
|
|
4831
5134
|
ch_driver_version = output
|
|
4832
5135
|
if driver_version == "keep":
|
|
4833
5136
|
driver_version = ch_driver_version
|
|
4834
|
-
elif path_chromedriver:
|
|
5137
|
+
elif path_chromedriver and not set_chromium:
|
|
4835
5138
|
try:
|
|
4836
5139
|
make_driver_executable_if_not(path_chromedriver)
|
|
4837
5140
|
except Exception as e:
|
|
@@ -5593,6 +5896,7 @@ def get_local_driver(
|
|
|
5593
5896
|
)
|
|
5594
5897
|
driver.default_get = driver.get # Save copy of original
|
|
5595
5898
|
driver.cdp = None # Set a placeholder
|
|
5899
|
+
driver._is_using_uc = False
|
|
5596
5900
|
driver._is_using_cdp = False
|
|
5597
5901
|
driver._is_connected = True
|
|
5598
5902
|
if uc_activated:
|
|
@@ -5627,6 +5931,7 @@ def get_local_driver(
|
|
|
5627
5931
|
driver, *args, **kwargs
|
|
5628
5932
|
)
|
|
5629
5933
|
)
|
|
5934
|
+
driver.activate_cdp_mode = driver.uc_activate_cdp_mode
|
|
5630
5935
|
driver.uc_open_with_cdp_mode = (
|
|
5631
5936
|
lambda *args, **kwargs: uc_open_with_cdp_mode(
|
|
5632
5937
|
driver, *args, **kwargs
|
|
@@ -5687,6 +5992,12 @@ def get_local_driver(
|
|
|
5687
5992
|
driver, *args, **kwargs
|
|
5688
5993
|
)
|
|
5689
5994
|
)
|
|
5995
|
+
driver.default_execute_cdp_cmd = driver.execute_cdp_cmd
|
|
5996
|
+
driver.execute_cdp_cmd = (
|
|
5997
|
+
lambda *args, **kwargs: uc_execute_cdp_cmd(
|
|
5998
|
+
driver, *args, **kwargs
|
|
5999
|
+
)
|
|
6000
|
+
)
|
|
5690
6001
|
driver._is_hidden = (headless or headless2)
|
|
5691
6002
|
driver._is_using_uc = True
|
|
5692
6003
|
with suppress(Exception):
|
|
@@ -5700,8 +6011,18 @@ def get_local_driver(
|
|
|
5700
6011
|
time.sleep(0.003)
|
|
5701
6012
|
driver.switch_to.window(driver.window_handles[0])
|
|
5702
6013
|
time.sleep(0.003)
|
|
5703
|
-
|
|
5704
|
-
|
|
6014
|
+
# seleniumbase/SeleniumBase/discussions/4190
|
|
6015
|
+
if getattr(sb_config, "skip_133_patch", None):
|
|
6016
|
+
# To skip the connect() patch for Chrome 133+:
|
|
6017
|
+
# from seleniumbase import config as sb_config
|
|
6018
|
+
# sb_config.skip_133_patch = True
|
|
6019
|
+
# (Do the above before launching the browser.)
|
|
6020
|
+
pass
|
|
6021
|
+
else:
|
|
6022
|
+
# This fixes an issue on Chrome 133+
|
|
6023
|
+
# (Some people might not need it though.)
|
|
6024
|
+
driver.connect()
|
|
6025
|
+
time.sleep(0.003)
|
|
5705
6026
|
if mobile_emulator:
|
|
5706
6027
|
uc_metrics = {}
|
|
5707
6028
|
if (
|
|
@@ -5729,6 +6050,8 @@ def get_local_driver(
|
|
|
5729
6050
|
'Emulation.setDeviceMetricsOverride',
|
|
5730
6051
|
set_device_metrics_override
|
|
5731
6052
|
)
|
|
6053
|
+
else:
|
|
6054
|
+
driver.get = lambda url: updated_get(driver, url)
|
|
5732
6055
|
return extend_driver(
|
|
5733
6056
|
driver, proxy_auth, use_uc, recorder_ext
|
|
5734
6057
|
)
|