seleniumbase 4.33.4__py3-none-any.whl → 4.34.2__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
Files changed (33) hide show
  1. seleniumbase/__version__.py +1 -1
  2. seleniumbase/behave/behave_sb.py +10 -2
  3. seleniumbase/console_scripts/run.py +6 -2
  4. seleniumbase/console_scripts/sb_commander.py +5 -5
  5. seleniumbase/console_scripts/sb_install.py +235 -6
  6. seleniumbase/console_scripts/sb_mkdir.py +1 -0
  7. seleniumbase/core/browser_launcher.py +358 -105
  8. seleniumbase/core/log_helper.py +33 -12
  9. seleniumbase/core/proxy_helper.py +35 -30
  10. seleniumbase/core/sb_cdp.py +277 -74
  11. seleniumbase/core/settings_parser.py +2 -0
  12. seleniumbase/core/style_sheet.py +10 -0
  13. seleniumbase/fixtures/base_case.py +216 -127
  14. seleniumbase/fixtures/constants.py +3 -0
  15. seleniumbase/fixtures/js_utils.py +2 -0
  16. seleniumbase/fixtures/page_actions.py +7 -2
  17. seleniumbase/fixtures/shared_utils.py +25 -0
  18. seleniumbase/plugins/driver_manager.py +28 -0
  19. seleniumbase/plugins/pytest_plugin.py +110 -0
  20. seleniumbase/plugins/sb_manager.py +41 -0
  21. seleniumbase/plugins/selenium_plugin.py +9 -0
  22. seleniumbase/undetected/cdp_driver/_contradict.py +3 -3
  23. seleniumbase/undetected/cdp_driver/browser.py +8 -6
  24. seleniumbase/undetected/cdp_driver/cdp_util.py +3 -0
  25. seleniumbase/undetected/cdp_driver/config.py +0 -1
  26. seleniumbase/undetected/cdp_driver/element.py +22 -20
  27. seleniumbase/undetected/patcher.py +20 -5
  28. {seleniumbase-4.33.4.dist-info → seleniumbase-4.34.2.dist-info}/LICENSE +1 -1
  29. {seleniumbase-4.33.4.dist-info → seleniumbase-4.34.2.dist-info}/METADATA +111 -86
  30. {seleniumbase-4.33.4.dist-info → seleniumbase-4.34.2.dist-info}/RECORD +33 -33
  31. {seleniumbase-4.33.4.dist-info → seleniumbase-4.34.2.dist-info}/WHEEL +1 -1
  32. {seleniumbase-4.33.4.dist-info → seleniumbase-4.34.2.dist-info}/entry_points.txt +0 -0
  33. {seleniumbase-4.33.4.dist-info → seleniumbase-4.34.2.dist-info}/top_level.txt +0 -0
@@ -1,6 +1,7 @@
1
1
  import fasteners
2
2
  import logging
3
3
  import os
4
+ import platform
4
5
  import re
5
6
  import shutil
6
7
  import subprocess
@@ -64,6 +65,7 @@ LOCAL_EDGEDRIVER = None
64
65
  LOCAL_IEDRIVER = None
65
66
  LOCAL_HEADLESS_IEDRIVER = None
66
67
  LOCAL_UC_DRIVER = None
68
+ ARCH = platform.architecture()[0]
67
69
  IS_ARM_MAC = shared_utils.is_arm_mac()
68
70
  IS_MAC = shared_utils.is_mac()
69
71
  IS_LINUX = shared_utils.is_linux()
@@ -97,26 +99,12 @@ def log_d(message):
97
99
  print(message)
98
100
 
99
101
 
100
- def make_writable(file_path):
101
- # Set permissions to: "If you can read it, you can write it."
102
- mode = os.stat(file_path).st_mode
103
- mode |= (mode & 0o444) >> 1 # copy R bits to W
104
- os.chmod(file_path, mode)
105
-
106
-
107
- def make_executable(file_path):
108
- # Set permissions to: "If you can read it, you can execute it."
109
- mode = os.stat(file_path).st_mode
110
- mode |= (mode & 0o444) >> 2 # copy R bits to X
111
- os.chmod(file_path, mode)
112
-
113
-
114
102
  def make_driver_executable_if_not(driver_path):
115
103
  # Verify driver has executable permissions. If not, add them.
116
104
  permissions = oct(os.stat(driver_path)[0])[-3:]
117
105
  if "4" in permissions or "6" in permissions:
118
106
  # We want at least a '5' or '7' to make sure it's executable
119
- make_executable(driver_path)
107
+ shared_utils.make_executable(driver_path)
120
108
 
121
109
 
122
110
  def extend_driver(driver):
@@ -547,10 +535,26 @@ def uc_open_with_cdp_mode(driver, url=None):
547
535
  if url_protocol not in ["about", "data", "chrome"]:
548
536
  safe_url = False
549
537
 
538
+ headless = False
539
+ headed = None
540
+ xvfb = None
541
+ if hasattr(sb_config, "headless"):
542
+ headless = sb_config.headless
543
+ if hasattr(sb_config, "headed"):
544
+ headed = sb_config.headed
545
+ if hasattr(sb_config, "xvfb"):
546
+ xvfb = sb_config.xvfb
547
+
550
548
  loop = asyncio.new_event_loop()
551
549
  asyncio.set_event_loop(loop)
552
550
  driver.cdp_base = loop.run_until_complete(
553
- cdp_util.start(host=cdp_host, port=cdp_port)
551
+ cdp_util.start(
552
+ host=cdp_host,
553
+ port=cdp_port,
554
+ headless=headless,
555
+ headed=headed,
556
+ xvfb=xvfb,
557
+ )
554
558
  )
555
559
  loop.run_until_complete(driver.cdp_base.wait(0))
556
560
 
@@ -566,6 +570,10 @@ def uc_open_with_cdp_mode(driver, url=None):
566
570
  for tab in driver.cdp_base.tabs[-1::-1]:
567
571
  if "chrome-extension://" not in str(tab):
568
572
  with gui_lock:
573
+ with suppress(Exception):
574
+ shared_utils.make_writable(
575
+ constants.MultiBrowser.PYAUTOGUILOCK
576
+ )
569
577
  loop.run_until_complete(tab.activate())
570
578
  break
571
579
 
@@ -580,11 +588,17 @@ def uc_open_with_cdp_mode(driver, url=None):
580
588
  if page_tab:
581
589
  loop.run_until_complete(page_tab.aopen())
582
590
  with gui_lock:
591
+ with suppress(Exception):
592
+ shared_utils.make_writable(
593
+ constants.MultiBrowser.PYAUTOGUILOCK
594
+ )
583
595
  loop.run_until_complete(page_tab.activate())
584
596
 
585
597
  loop.run_until_complete(driver.cdp_base.update_targets())
586
598
  page = loop.run_until_complete(driver.cdp_base.get(url))
587
599
  with gui_lock:
600
+ with suppress(Exception):
601
+ shared_utils.make_writable(constants.MultiBrowser.PYAUTOGUILOCK)
588
602
  loop.run_until_complete(page.activate())
589
603
  loop.run_until_complete(page.wait())
590
604
  if not safe_url:
@@ -604,6 +618,7 @@ def uc_open_with_cdp_mode(driver, url=None):
604
618
  cdp.find_element = CDPM.find_element
605
619
  cdp.find = CDPM.find_element
606
620
  cdp.locator = CDPM.find_element
621
+ cdp.find_element_by_text = CDPM.find_element_by_text
607
622
  cdp.find_all = CDPM.find_all
608
623
  cdp.find_elements_by_text = CDPM.find_elements_by_text
609
624
  cdp.select = CDPM.select
@@ -662,6 +677,7 @@ def uc_open_with_cdp_mode(driver, url=None):
662
677
  cdp.get_window = CDPM.get_window
663
678
  cdp.get_element_attributes = CDPM.get_element_attributes
664
679
  cdp.get_element_attribute = CDPM.get_element_attribute
680
+ cdp.get_attribute = CDPM.get_attribute
665
681
  cdp.get_element_html = CDPM.get_element_html
666
682
  cdp.get_element_rect = CDPM.get_element_rect
667
683
  cdp.get_element_size = CDPM.get_element_size
@@ -817,6 +833,72 @@ def verify_pyautogui_has_a_headed_browser(driver):
817
833
  )
818
834
 
819
835
 
836
+ def __install_pyautogui_if_missing():
837
+ try:
838
+ import pyautogui
839
+ with suppress(Exception):
840
+ use_pyautogui_ver = constants.PyAutoGUI.VER
841
+ if pyautogui.__version__ != use_pyautogui_ver:
842
+ del pyautogui
843
+ shared_utils.pip_install(
844
+ "pyautogui", version=use_pyautogui_ver
845
+ )
846
+ import pyautogui
847
+ except Exception:
848
+ print("\nPyAutoGUI required! Installing now...")
849
+ shared_utils.pip_install(
850
+ "pyautogui", version=constants.PyAutoGUI.VER
851
+ )
852
+ try:
853
+ import pyautogui
854
+ except Exception:
855
+ if (
856
+ IS_LINUX
857
+ and hasattr(sb_config, "xvfb")
858
+ and hasattr(sb_config, "headed")
859
+ and hasattr(sb_config, "headless")
860
+ and hasattr(sb_config, "headless2")
861
+ and (not sb_config.headed or sb_config.xvfb)
862
+ and not (sb_config.headless or sb_config.headless2)
863
+ ):
864
+ from sbvirtualdisplay import Display
865
+ xvfb_width = 1366
866
+ xvfb_height = 768
867
+ if (
868
+ hasattr(sb_config, "_xvfb_width")
869
+ and sb_config._xvfb_width
870
+ and isinstance(sb_config._xvfb_width, int)
871
+ and hasattr(sb_config, "_xvfb_height")
872
+ and sb_config._xvfb_height
873
+ and isinstance(sb_config._xvfb_height, int)
874
+ ):
875
+ xvfb_width = sb_config._xvfb_width
876
+ xvfb_height = sb_config._xvfb_height
877
+ if xvfb_width < 1024:
878
+ xvfb_width = 1024
879
+ sb_config._xvfb_width = xvfb_width
880
+ if xvfb_height < 768:
881
+ xvfb_height = 768
882
+ sb_config._xvfb_height = xvfb_height
883
+ with suppress(Exception):
884
+ _xvfb_display = Display(
885
+ visible=True,
886
+ size=(xvfb_width, xvfb_height),
887
+ backend="xvfb",
888
+ use_xauth=True,
889
+ )
890
+ _xvfb_display.start()
891
+ sb_config._virtual_display = _xvfb_display
892
+ sb_config.headless_active = True
893
+ if (
894
+ hasattr(sb_config, "reuse_session")
895
+ and sb_config.reuse_session
896
+ and hasattr(sb_config, "_vd_list")
897
+ and isinstance(sb_config._vd_list, list)
898
+ ):
899
+ sb_config._vd_list.append(_xvfb_display)
900
+
901
+
820
902
  def install_pyautogui_if_missing(driver):
821
903
  verify_pyautogui_has_a_headed_browser(driver)
822
904
  pip_find_lock = fasteners.InterProcessLock(
@@ -826,64 +908,13 @@ def install_pyautogui_if_missing(driver):
826
908
  with pip_find_lock:
827
909
  pass
828
910
  except Exception:
829
- # Need write permissions
830
- with suppress(Exception):
831
- make_writable(constants.PipInstall.FINDLOCK)
911
+ # Since missing permissions, skip the locks
912
+ __install_pyautogui_if_missing()
913
+ return
832
914
  with pip_find_lock: # Prevent issues with multiple processes
833
- try:
834
- import pyautogui
835
- with suppress(Exception):
836
- use_pyautogui_ver = constants.PyAutoGUI.VER
837
- if pyautogui.__version__ != use_pyautogui_ver:
838
- del pyautogui
839
- shared_utils.pip_install(
840
- "pyautogui", version=use_pyautogui_ver
841
- )
842
- import pyautogui
843
- except Exception:
844
- print("\nPyAutoGUI required! Installing now...")
845
- shared_utils.pip_install(
846
- "pyautogui", version=constants.PyAutoGUI.VER
847
- )
848
- try:
849
- import pyautogui
850
- except Exception:
851
- if (
852
- IS_LINUX
853
- and hasattr(sb_config, "xvfb")
854
- and hasattr(sb_config, "headed")
855
- and hasattr(sb_config, "headless")
856
- and hasattr(sb_config, "headless2")
857
- and (not sb_config.headed or sb_config.xvfb)
858
- and not (sb_config.headless or sb_config.headless2)
859
- ):
860
- from sbvirtualdisplay import Display
861
- xvfb_width = 1366
862
- xvfb_height = 768
863
- if (
864
- hasattr(sb_config, "_xvfb_width")
865
- and sb_config._xvfb_width
866
- and isinstance(sb_config._xvfb_width, int)
867
- and hasattr(sb_config, "_xvfb_height")
868
- and sb_config._xvfb_height
869
- and isinstance(sb_config._xvfb_height, int)
870
- ):
871
- xvfb_width = sb_config._xvfb_width
872
- xvfb_height = sb_config._xvfb_height
873
- if xvfb_width < 1024:
874
- xvfb_width = 1024
875
- sb_config._xvfb_width = xvfb_width
876
- if xvfb_height < 768:
877
- xvfb_height = 768
878
- sb_config._xvfb_height = xvfb_height
879
- with suppress(Exception):
880
- xvfb_display = Display(
881
- visible=True,
882
- size=(xvfb_width, xvfb_height),
883
- backend="xvfb",
884
- use_xauth=True,
885
- )
886
- xvfb_display.start()
915
+ with suppress(Exception):
916
+ shared_utils.make_writable(constants.PipInstall.FINDLOCK)
917
+ __install_pyautogui_if_missing()
887
918
 
888
919
 
889
920
  def get_configured_pyautogui(pyautogui_copy):
@@ -1195,6 +1226,13 @@ def _uc_gui_click_captcha(
1195
1226
  and driver.is_element_present("#challenge-form div > div")
1196
1227
  ):
1197
1228
  frame = "#challenge-form div > div"
1229
+ elif (
1230
+ driver.is_element_present('[name*="cf-turnstile-"]')
1231
+ and driver.is_element_present(
1232
+ '[style="display: grid;"] div div'
1233
+ )
1234
+ ):
1235
+ frame = '[style="display: grid;"] div div'
1198
1236
  elif (
1199
1237
  driver.is_element_present('[name*="cf-turnstile-"]')
1200
1238
  and driver.is_element_present("[class*=spacer] + div div")
@@ -1411,7 +1449,7 @@ def _uc_gui_handle_captcha_(driver, frame="iframe", ctype=None):
1411
1449
  ctype = "cf_t"
1412
1450
  else:
1413
1451
  return
1414
- if not driver.is_connected():
1452
+ if not driver.is_connected() and not __is_cdp_swap_needed(driver):
1415
1453
  driver.connect()
1416
1454
  time.sleep(2)
1417
1455
  install_pyautogui_if_missing(driver)
@@ -1423,7 +1461,10 @@ def _uc_gui_handle_captcha_(driver, frame="iframe", ctype=None):
1423
1461
  )
1424
1462
  with gui_lock: # Prevent issues with multiple processes
1425
1463
  needs_switch = False
1426
- is_in_frame = js_utils.is_in_frame(driver)
1464
+ if not __is_cdp_swap_needed(driver):
1465
+ is_in_frame = js_utils.is_in_frame(driver)
1466
+ else:
1467
+ is_in_frame = False
1427
1468
  selector = "#challenge-stage"
1428
1469
  if ctype == "g_rc":
1429
1470
  selector = "#recaptcha-token"
@@ -1431,7 +1472,7 @@ def _uc_gui_handle_captcha_(driver, frame="iframe", ctype=None):
1431
1472
  driver.switch_to.parent_frame()
1432
1473
  needs_switch = True
1433
1474
  is_in_frame = js_utils.is_in_frame(driver)
1434
- if not is_in_frame:
1475
+ if not is_in_frame and not __is_cdp_swap_needed(driver):
1435
1476
  # Make sure the window is on top
1436
1477
  page_actions.switch_to_window(
1437
1478
  driver, driver.current_window_handle, 2, uc_lock=False
@@ -1498,17 +1539,18 @@ def _uc_gui_handle_captcha_(driver, frame="iframe", ctype=None):
1498
1539
  and frame == "iframe"
1499
1540
  ):
1500
1541
  frame = 'iframe[title="reCAPTCHA"]'
1501
- if not is_in_frame or needs_switch:
1502
- # Currently not in frame (or nested frame outside CF one)
1503
- try:
1504
- if visible_iframe or ctype == "g_rc":
1505
- driver.switch_to_frame(frame)
1506
- except Exception:
1507
- if visible_iframe or ctype == "g_rc":
1508
- if driver.is_element_present("iframe"):
1509
- driver.switch_to_frame("iframe")
1510
- else:
1511
- return
1542
+ if not __is_cdp_swap_needed(driver):
1543
+ if not is_in_frame or needs_switch:
1544
+ # Currently not in frame (or nested frame outside CF one)
1545
+ try:
1546
+ if visible_iframe or ctype == "g_rc":
1547
+ driver.switch_to_frame(frame)
1548
+ except Exception:
1549
+ if visible_iframe or ctype == "g_rc":
1550
+ if driver.is_element_present("iframe"):
1551
+ driver.switch_to_frame("iframe")
1552
+ else:
1553
+ return
1512
1554
  try:
1513
1555
  selector = "div.cf-turnstile"
1514
1556
  if ctype == "g_rc":
@@ -1518,17 +1560,20 @@ def _uc_gui_handle_captcha_(driver, frame="iframe", ctype=None):
1518
1560
  for i in range(10):
1519
1561
  pyautogui.hotkey("shift", "tab")
1520
1562
  time.sleep(0.027)
1563
+ if ctype == "g_rc":
1564
+ if js_utils.get_active_element_css(driver) == "body":
1565
+ break
1521
1566
  tab_count = 0
1522
1567
  for i in range(34):
1523
1568
  pyautogui.press("\t")
1524
1569
  tab_count += 1
1525
1570
  time.sleep(0.027)
1526
1571
  active_element_css = js_utils.get_active_element_css(driver)
1527
- print(active_element_css)
1528
1572
  if (
1529
1573
  active_element_css.startswith(selector)
1530
1574
  or active_element_css.endswith(" > div" * 2)
1531
1575
  or (special_form and active_element_css.endswith(" div"))
1576
+ or (ctype == "g_rc" and "frame[name" in active_element_css)
1532
1577
  ):
1533
1578
  found_checkbox = True
1534
1579
  sb_config._saved_cf_tab_count = tab_count
@@ -1548,6 +1593,7 @@ def _uc_gui_handle_captcha_(driver, frame="iframe", ctype=None):
1548
1593
  )
1549
1594
  and hasattr(sb_config, "_saved_cf_tab_count")
1550
1595
  and sb_config._saved_cf_tab_count
1596
+ and not __is_cdp_swap_needed(driver)
1551
1597
  ):
1552
1598
  driver.uc_open_with_disconnect(driver.current_url, 3.8)
1553
1599
  with suppress(Exception):
@@ -1762,22 +1808,34 @@ def _add_chrome_proxy_extension(
1762
1808
  ):
1763
1809
  # Single-threaded
1764
1810
  if zip_it:
1765
- proxy_helper.create_proxy_ext(
1766
- proxy_string, proxy_user, proxy_pass, bypass_list
1767
- )
1768
- proxy_zip = proxy_helper.PROXY_ZIP_PATH
1769
- chrome_options.add_extension(proxy_zip)
1811
+ proxy_zip_lock = fasteners.InterProcessLock(PROXY_ZIP_LOCK)
1812
+ with proxy_zip_lock:
1813
+ proxy_helper.create_proxy_ext(
1814
+ proxy_string, proxy_user, proxy_pass, bypass_list
1815
+ )
1816
+ proxy_zip = proxy_helper.PROXY_ZIP_PATH
1817
+ chrome_options.add_extension(proxy_zip)
1770
1818
  else:
1771
- proxy_helper.create_proxy_ext(
1772
- proxy_string, proxy_user, proxy_pass, bypass_list, zip_it=False
1773
- )
1774
- proxy_dir_path = proxy_helper.PROXY_DIR_PATH
1775
- chrome_options = add_chrome_ext_dir(chrome_options, proxy_dir_path)
1819
+ proxy_dir_lock = fasteners.InterProcessLock(PROXY_DIR_LOCK)
1820
+ with proxy_dir_lock:
1821
+ proxy_helper.create_proxy_ext(
1822
+ proxy_string,
1823
+ proxy_user,
1824
+ proxy_pass,
1825
+ bypass_list,
1826
+ zip_it=False,
1827
+ )
1828
+ proxy_dir_path = proxy_helper.PROXY_DIR_PATH
1829
+ chrome_options = add_chrome_ext_dir(
1830
+ chrome_options, proxy_dir_path
1831
+ )
1776
1832
  else:
1777
1833
  # Multi-threaded
1778
1834
  if zip_it:
1779
1835
  proxy_zip_lock = fasteners.InterProcessLock(PROXY_ZIP_LOCK)
1780
1836
  with proxy_zip_lock:
1837
+ with suppress(Exception):
1838
+ shared_utils.make_writable(PROXY_ZIP_LOCK)
1781
1839
  if multi_proxy:
1782
1840
  _set_proxy_filenames()
1783
1841
  if not os.path.exists(proxy_helper.PROXY_ZIP_PATH):
@@ -1789,6 +1847,8 @@ def _add_chrome_proxy_extension(
1789
1847
  else:
1790
1848
  proxy_dir_lock = fasteners.InterProcessLock(PROXY_DIR_LOCK)
1791
1849
  with proxy_dir_lock:
1850
+ with suppress(Exception):
1851
+ shared_utils.make_writable(PROXY_DIR_LOCK)
1792
1852
  if multi_proxy:
1793
1853
  _set_proxy_filenames()
1794
1854
  if not os.path.exists(proxy_helper.PROXY_DIR_PATH):
@@ -1797,7 +1857,7 @@ def _add_chrome_proxy_extension(
1797
1857
  proxy_user,
1798
1858
  proxy_pass,
1799
1859
  bypass_list,
1800
- False,
1860
+ zip_it=False,
1801
1861
  )
1802
1862
  chrome_options = add_chrome_ext_dir(
1803
1863
  chrome_options, proxy_helper.PROXY_DIR_PATH
@@ -1814,6 +1874,8 @@ def is_using_uc(undetectable, browser_name):
1814
1874
  def _unzip_to_new_folder(zip_file, folder):
1815
1875
  proxy_dir_lock = fasteners.InterProcessLock(PROXY_DIR_LOCK)
1816
1876
  with proxy_dir_lock:
1877
+ with suppress(Exception):
1878
+ shared_utils.make_writable(PROXY_DIR_LOCK)
1817
1879
  if not os.path.exists(folder):
1818
1880
  import zipfile
1819
1881
  zip_ref = zipfile.ZipFile(zip_file, "r")
@@ -2298,7 +2360,6 @@ def _set_chrome_options(
2298
2360
  chrome_options.add_argument("--disable-ipc-flooding-protection")
2299
2361
  chrome_options.add_argument("--disable-password-generation")
2300
2362
  chrome_options.add_argument("--disable-domain-reliability")
2301
- chrome_options.add_argument("--disable-component-update")
2302
2363
  chrome_options.add_argument("--disable-breakpad")
2303
2364
  included_disabled_features = []
2304
2365
  included_disabled_features.append("OptimizationHints")
@@ -2383,8 +2444,6 @@ def _set_firefox_options(
2383
2444
  options.set_preference("dom.webnotifications.enabled", False)
2384
2445
  options.set_preference("dom.disable_beforeunload", True)
2385
2446
  options.set_preference("browser.contentblocking.database.enabled", True)
2386
- options.set_preference("extensions.allowPrivateBrowsingByDefault", True)
2387
- options.set_preference("extensions.PrivateBrowsing.notification", False)
2388
2447
  options.set_preference("extensions.systemAddon.update.enabled", False)
2389
2448
  options.set_preference("extensions.update.autoUpdateDefault", False)
2390
2449
  options.set_preference("extensions.update.enabled", False)
@@ -2600,6 +2659,118 @@ def get_driver(
2600
2659
  or browser_name == constants.Browser.EDGE
2601
2660
  )
2602
2661
  ):
2662
+ if (
2663
+ binary_location.lower() == "cft"
2664
+ and browser_name == constants.Browser.GOOGLE_CHROME
2665
+ ):
2666
+ binary_folder = None
2667
+ if IS_MAC:
2668
+ if IS_ARM_MAC:
2669
+ binary_folder = "chrome-mac-arm64"
2670
+ else:
2671
+ binary_folder = "chrome-mac-x64"
2672
+ elif IS_LINUX:
2673
+ binary_folder = "chrome-linux64"
2674
+ elif IS_WINDOWS:
2675
+ if "64" in ARCH:
2676
+ binary_folder = "chrome-win64"
2677
+ else:
2678
+ binary_folder = "chrome-win32"
2679
+ if binary_folder:
2680
+ binary_location = os.path.join(DRIVER_DIR, binary_folder)
2681
+ if not os.path.exists(binary_location):
2682
+ from seleniumbase.console_scripts import sb_install
2683
+ args = " ".join(sys.argv)
2684
+ if not (
2685
+ "-n" in sys.argv or " -n=" in args or args == "-c"
2686
+ ):
2687
+ # (Not multithreaded)
2688
+ sys_args = sys.argv # Save a copy of current sys args
2689
+ log_d(
2690
+ "\nWarning: Chrome for Testing binary not found..."
2691
+ )
2692
+ try:
2693
+ sb_install.main(override="cft")
2694
+ except Exception as e:
2695
+ log_d("\nWarning: Chrome download failed: %s" % e)
2696
+ sys.argv = sys_args # Put back the original sys args
2697
+ else:
2698
+ chrome_fixing_lock = fasteners.InterProcessLock(
2699
+ constants.MultiBrowser.DRIVER_FIXING_LOCK
2700
+ )
2701
+ with chrome_fixing_lock:
2702
+ with suppress(Exception):
2703
+ shared_utils.make_writable(
2704
+ constants.MultiBrowser.DRIVER_FIXING_LOCK
2705
+ )
2706
+ if not os.path.exists(binary_location):
2707
+ sys_args = sys.argv # Save a copy of sys args
2708
+ log_d(
2709
+ "\nWarning: "
2710
+ "Chrome for Testing binary not found..."
2711
+ )
2712
+ sb_install.main(override="cft")
2713
+ sys.argv = sys_args # Put back original args
2714
+ else:
2715
+ binary_location = None
2716
+ if (
2717
+ binary_location.lower() == "chs"
2718
+ and browser_name == constants.Browser.GOOGLE_CHROME
2719
+ ):
2720
+ binary_folder = None
2721
+ if IS_MAC:
2722
+ if IS_ARM_MAC:
2723
+ binary_folder = "chrome-headless-shell-mac-arm64"
2724
+ else:
2725
+ binary_folder = "chrome-headless-shell-mac-x64"
2726
+ elif IS_LINUX:
2727
+ binary_folder = "chrome-headless-shell-linux64"
2728
+ elif IS_WINDOWS:
2729
+ if "64" in ARCH:
2730
+ binary_folder = "chrome-headless-shell-win64"
2731
+ else:
2732
+ binary_folder = "chrome-headless-shell-win32"
2733
+ if binary_folder:
2734
+ binary_location = os.path.join(DRIVER_DIR, binary_folder)
2735
+ if not os.path.exists(binary_location):
2736
+ from seleniumbase.console_scripts import sb_install
2737
+ args = " ".join(sys.argv)
2738
+ if not (
2739
+ "-n" in sys.argv or " -n=" in args or args == "-c"
2740
+ ):
2741
+ # (Not multithreaded)
2742
+ sys_args = sys.argv # Save a copy of current sys args
2743
+ log_d(
2744
+ "\nWarning: "
2745
+ "Chrome-Headless-Shell binary not found..."
2746
+ )
2747
+ try:
2748
+ sb_install.main(override="chs")
2749
+ except Exception as e:
2750
+ log_d(
2751
+ "\nWarning: "
2752
+ "Chrome-Headless-Shell download failed: %s" % e
2753
+ )
2754
+ sys.argv = sys_args # Put back the original sys args
2755
+ else:
2756
+ chrome_fixing_lock = fasteners.InterProcessLock(
2757
+ constants.MultiBrowser.DRIVER_FIXING_LOCK
2758
+ )
2759
+ with chrome_fixing_lock:
2760
+ with suppress(Exception):
2761
+ shared_utils.make_writable(
2762
+ constants.MultiBrowser.DRIVER_FIXING_LOCK
2763
+ )
2764
+ if not os.path.exists(binary_location):
2765
+ sys_args = sys.argv # Save a copy of sys args
2766
+ log_d(
2767
+ "\nWarning: "
2768
+ "Chrome-Headless-Shell binary not found..."
2769
+ )
2770
+ sb_install.main(override="chs")
2771
+ sys.argv = sys_args # Put back original args
2772
+ else:
2773
+ binary_location = None
2603
2774
  if not os.path.exists(binary_location):
2604
2775
  log_d(
2605
2776
  "\nWarning: The Chromium binary specified (%s) was NOT found!"
@@ -2609,7 +2780,7 @@ def get_driver(
2609
2780
  elif binary_location.endswith("/") or binary_location.endswith("\\"):
2610
2781
  log_d(
2611
2782
  "\nWarning: The Chromium binary path must be a full path "
2612
- "that includes the driver filename at the end of it!"
2783
+ "that includes the browser filename at the end of it!"
2613
2784
  "\n(Will use default settings...)\n" % binary_location
2614
2785
  )
2615
2786
  # Example of a valid binary location path - MacOS:
@@ -2618,6 +2789,34 @@ def get_driver(
2618
2789
  else:
2619
2790
  binary_name = binary_location.split("/")[-1].split("\\")[-1]
2620
2791
  valid_names = get_valid_binary_names_for_browser(browser_name)
2792
+ if binary_name == "Google Chrome for Testing.app":
2793
+ binary_name = "Google Chrome for Testing"
2794
+ binary_location += "/Contents/MacOS/Google Chrome for Testing"
2795
+ elif binary_name in ["chrome-mac-arm64", "chrome-mac-x64"]:
2796
+ binary_name = "Google Chrome for Testing"
2797
+ binary_location += "/Google Chrome for Testing.app"
2798
+ binary_location += "/Contents/MacOS/Google Chrome for Testing"
2799
+ elif binary_name == "chrome-linux64":
2800
+ binary_name = "chrome"
2801
+ binary_location += "/chrome"
2802
+ elif binary_name in ["chrome-win32", "chrome-win64"]:
2803
+ binary_name = "chrome.exe"
2804
+ binary_location += "\\chrome.exe"
2805
+ elif binary_name in [
2806
+ "chrome-headless-shell-mac-arm64",
2807
+ "chrome-headless-shell-mac-x64",
2808
+ ]:
2809
+ binary_name = "chrome-headless-shell"
2810
+ binary_location += "/chrome-headless-shell"
2811
+ elif binary_name == "chrome-headless-shell-linux64":
2812
+ binary_name = "chrome-headless-shell"
2813
+ binary_location += "/chrome-headless-shell"
2814
+ elif binary_name in [
2815
+ "chrome-headless-shell-win32",
2816
+ "chrome-headless-shell-win64",
2817
+ ]:
2818
+ binary_name = "chrome-headless-shell.exe"
2819
+ binary_location += "\\chrome-headless-shell.exe"
2621
2820
  if binary_name not in valid_names:
2622
2821
  log_d(
2623
2822
  "\nWarning: The Chromium binary specified is NOT valid!"
@@ -2626,6 +2825,8 @@ def get_driver(
2626
2825
  "" % (binary_name, valid_names)
2627
2826
  )
2628
2827
  binary_location = None
2828
+ elif binary_location.lower() == "chs":
2829
+ headless = True
2629
2830
  if (uc_cdp_events or uc_subprocess) and not undetectable:
2630
2831
  undetectable = True
2631
2832
  if mobile_emulator and not user_agent:
@@ -2923,6 +3124,8 @@ def get_remote_driver(
2923
3124
  constants.PipInstall.FINDLOCK
2924
3125
  )
2925
3126
  with pip_find_lock: # Prevent issues with multiple processes
3127
+ with suppress(Exception):
3128
+ shared_utils.make_writable(constants.PipInstall.FINDLOCK)
2926
3129
  try:
2927
3130
  from seleniumwire import webdriver
2928
3131
  import blinker
@@ -3360,6 +3563,8 @@ def get_local_driver(
3360
3563
  constants.PipInstall.FINDLOCK
3361
3564
  )
3362
3565
  with pip_find_lock: # Prevent issues with multiple processes
3566
+ with suppress(Exception):
3567
+ shared_utils.make_writable(constants.PipInstall.FINDLOCK)
3363
3568
  try:
3364
3569
  from seleniumwire import webdriver
3365
3570
  import blinker
@@ -3423,6 +3628,10 @@ def get_local_driver(
3423
3628
  constants.MultiBrowser.DRIVER_FIXING_LOCK
3424
3629
  )
3425
3630
  with geckodriver_fixing_lock:
3631
+ with suppress(Exception):
3632
+ shared_utils.make_writable(
3633
+ constants.MultiBrowser.DRIVER_FIXING_LOCK
3634
+ )
3426
3635
  if not geckodriver_on_path():
3427
3636
  sys_args = sys.argv # Save a copy of sys args
3428
3637
  log_d(
@@ -3725,6 +3934,10 @@ def get_local_driver(
3725
3934
  constants.MultiBrowser.DRIVER_FIXING_LOCK
3726
3935
  )
3727
3936
  with edgedriver_fixing_lock:
3937
+ with suppress(Exception):
3938
+ shared_utils.make_writable(
3939
+ constants.MultiBrowser.DRIVER_FIXING_LOCK
3940
+ )
3728
3941
  msg = "Microsoft Edge Driver not found."
3729
3942
  if edgedriver_upgrade_needed:
3730
3943
  msg = "Microsoft Edge Driver update needed."
@@ -3783,6 +3996,12 @@ def get_local_driver(
3783
3996
  edge_options.add_argument("--guest")
3784
3997
  if dark_mode:
3785
3998
  edge_options.add_argument("--enable-features=WebContentsForceDark")
3999
+ if headless1:
4000
+ # developer.chrome.com/blog/removing-headless-old-from-chrome
4001
+ with suppress(Exception):
4002
+ if int(str(use_version).split(".")[0]) >= 132:
4003
+ headless1 = False
4004
+ headless2 = True
3786
4005
  if headless2:
3787
4006
  try:
3788
4007
  if use_version == "latest" or int(use_version) >= 109:
@@ -4036,7 +4255,6 @@ def get_local_driver(
4036
4255
  edge_options.add_argument("--disable-ipc-flooding-protection")
4037
4256
  edge_options.add_argument("--disable-password-generation")
4038
4257
  edge_options.add_argument("--disable-domain-reliability")
4039
- edge_options.add_argument("--disable-component-update")
4040
4258
  edge_options.add_argument("--disable-breakpad")
4041
4259
  included_disabled_features = []
4042
4260
  included_disabled_features.append("OptimizationHints")
@@ -4108,6 +4326,10 @@ def get_local_driver(
4108
4326
  constants.MultiBrowser.DRIVER_FIXING_LOCK
4109
4327
  )
4110
4328
  with edgedriver_fixing_lock:
4329
+ with suppress(Exception):
4330
+ shared_utils.make_writable(
4331
+ constants.MultiBrowser.DRIVER_FIXING_LOCK
4332
+ )
4111
4333
  with suppress(Exception):
4112
4334
  if not _was_driver_repaired():
4113
4335
  _repair_edgedriver(edge_version)
@@ -4321,6 +4543,12 @@ def get_local_driver(
4321
4543
  use_version = find_chromedriver_version_to_use(
4322
4544
  use_version, driver_version
4323
4545
  )
4546
+ if headless1:
4547
+ # developer.chrome.com/blog/removing-headless-old-from-chrome
4548
+ with suppress(Exception):
4549
+ if int(str(use_version).split(".")[0]) >= 132:
4550
+ headless1 = False
4551
+ headless2 = True
4324
4552
  if headless2:
4325
4553
  try:
4326
4554
  if (
@@ -4490,6 +4718,10 @@ def get_local_driver(
4490
4718
  constants.MultiBrowser.DRIVER_FIXING_LOCK
4491
4719
  )
4492
4720
  with chromedriver_fixing_lock:
4721
+ with suppress(Exception):
4722
+ shared_utils.make_writable(
4723
+ constants.MultiBrowser.DRIVER_FIXING_LOCK
4724
+ )
4493
4725
  msg = "chromedriver update needed. Getting it now:"
4494
4726
  if not path_chromedriver:
4495
4727
  msg = "chromedriver not found. Getting it now:"
@@ -4581,6 +4813,10 @@ def get_local_driver(
4581
4813
  constants.MultiBrowser.DRIVER_FIXING_LOCK
4582
4814
  )
4583
4815
  with uc_lock: # Avoid multithreaded issues
4816
+ with suppress(Exception):
4817
+ shared_utils.make_writable(
4818
+ constants.MultiBrowser.DRIVER_FIXING_LOCK
4819
+ )
4584
4820
  if make_uc_driver_from_chromedriver:
4585
4821
  if os.path.exists(LOCAL_CHROMEDRIVER):
4586
4822
  with suppress(Exception):
@@ -4813,7 +5049,13 @@ def get_local_driver(
4813
5049
  )
4814
5050
  uc_activated = True
4815
5051
  except URLError as e:
4816
- if cert in e.args[0] and IS_MAC:
5052
+ if (
5053
+ IS_MAC
5054
+ and hasattr(e, "args")
5055
+ and isinstance(e.args, (list, tuple))
5056
+ and len(e.args) > 0
5057
+ and cert in e.args[0]
5058
+ ):
4817
5059
  mac_certificate_error = True
4818
5060
  else:
4819
5061
  raise
@@ -4840,6 +5082,10 @@ def get_local_driver(
4840
5082
  if not os.path.exists(cf_lock_path):
4841
5083
  # Avoid multithreaded issues
4842
5084
  with cf_lock:
5085
+ with suppress(Exception):
5086
+ shared_utils.make_writable(
5087
+ cf_lock_path
5088
+ )
4843
5089
  # Install Python Certificates (MAC)
4844
5090
  os.system(
4845
5091
  r"bash /Applications/Python*/"
@@ -4983,6 +5229,10 @@ def get_local_driver(
4983
5229
  constants.MultiBrowser.DRIVER_FIXING_LOCK
4984
5230
  )
4985
5231
  with chromedriver_fixing_lock:
5232
+ with suppress(Exception):
5233
+ shared_utils.make_writable(
5234
+ constants.MultiBrowser.DRIVER_FIXING_LOCK
5235
+ )
4986
5236
  if not _was_driver_repaired():
4987
5237
  _repair_chromedriver(
4988
5238
  chrome_options, headless_options, mcv
@@ -5181,7 +5431,10 @@ def get_local_driver(
5181
5431
  chromedr_fixing_lock = fasteners.InterProcessLock(
5182
5432
  constants.MultiBrowser.DRIVER_FIXING_LOCK
5183
5433
  )
5434
+ D_F_L = constants.MultiBrowser.DRIVER_FIXING_LOCK
5184
5435
  with chromedr_fixing_lock:
5436
+ with suppress(Exception):
5437
+ shared_utils.make_writable(D_F_L)
5185
5438
  if not _was_driver_repaired():
5186
5439
  with suppress(Exception):
5187
5440
  _repair_chromedriver(