seleniumbase 4.24.10__py3-none-any.whl → 4.33.15__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
Files changed (79) hide show
  1. sbase/__init__.py +1 -0
  2. sbase/steps.py +7 -0
  3. seleniumbase/__init__.py +16 -7
  4. seleniumbase/__version__.py +1 -1
  5. seleniumbase/behave/behave_sb.py +97 -32
  6. seleniumbase/common/decorators.py +16 -7
  7. seleniumbase/config/proxy_list.py +3 -3
  8. seleniumbase/config/settings.py +4 -0
  9. seleniumbase/console_scripts/logo_helper.py +47 -8
  10. seleniumbase/console_scripts/run.py +345 -335
  11. seleniumbase/console_scripts/sb_behave_gui.py +5 -12
  12. seleniumbase/console_scripts/sb_caseplans.py +6 -13
  13. seleniumbase/console_scripts/sb_commander.py +5 -12
  14. seleniumbase/console_scripts/sb_install.py +62 -54
  15. seleniumbase/console_scripts/sb_mkchart.py +13 -20
  16. seleniumbase/console_scripts/sb_mkdir.py +11 -17
  17. seleniumbase/console_scripts/sb_mkfile.py +69 -43
  18. seleniumbase/console_scripts/sb_mkpres.py +13 -20
  19. seleniumbase/console_scripts/sb_mkrec.py +88 -21
  20. seleniumbase/console_scripts/sb_objectify.py +30 -30
  21. seleniumbase/console_scripts/sb_print.py +5 -12
  22. seleniumbase/console_scripts/sb_recorder.py +16 -11
  23. seleniumbase/core/browser_launcher.py +1658 -221
  24. seleniumbase/core/detect_b_ver.py +7 -8
  25. seleniumbase/core/log_helper.py +42 -27
  26. seleniumbase/core/mysql.py +1 -4
  27. seleniumbase/core/proxy_helper.py +35 -30
  28. seleniumbase/core/recorder_helper.py +24 -5
  29. seleniumbase/core/sb_cdp.py +1951 -0
  30. seleniumbase/core/sb_driver.py +162 -8
  31. seleniumbase/core/settings_parser.py +6 -0
  32. seleniumbase/core/style_sheet.py +10 -0
  33. seleniumbase/extensions/recorder.zip +0 -0
  34. seleniumbase/fixtures/base_case.py +1234 -632
  35. seleniumbase/fixtures/constants.py +10 -1
  36. seleniumbase/fixtures/js_utils.py +171 -144
  37. seleniumbase/fixtures/page_actions.py +177 -13
  38. seleniumbase/fixtures/page_utils.py +25 -53
  39. seleniumbase/fixtures/shared_utils.py +97 -11
  40. seleniumbase/js_code/active_css_js.py +1 -1
  41. seleniumbase/js_code/recorder_js.py +1 -1
  42. seleniumbase/plugins/base_plugin.py +2 -3
  43. seleniumbase/plugins/driver_manager.py +340 -65
  44. seleniumbase/plugins/pytest_plugin.py +276 -47
  45. seleniumbase/plugins/sb_manager.py +412 -99
  46. seleniumbase/plugins/selenium_plugin.py +122 -17
  47. seleniumbase/translate/translator.py +0 -7
  48. seleniumbase/undetected/__init__.py +59 -52
  49. seleniumbase/undetected/cdp.py +0 -1
  50. seleniumbase/undetected/cdp_driver/__init__.py +1 -0
  51. seleniumbase/undetected/cdp_driver/_contradict.py +110 -0
  52. seleniumbase/undetected/cdp_driver/browser.py +829 -0
  53. seleniumbase/undetected/cdp_driver/cdp_util.py +458 -0
  54. seleniumbase/undetected/cdp_driver/config.py +334 -0
  55. seleniumbase/undetected/cdp_driver/connection.py +639 -0
  56. seleniumbase/undetected/cdp_driver/element.py +1168 -0
  57. seleniumbase/undetected/cdp_driver/tab.py +1323 -0
  58. seleniumbase/undetected/dprocess.py +4 -7
  59. seleniumbase/undetected/options.py +6 -8
  60. seleniumbase/undetected/patcher.py +11 -13
  61. seleniumbase/undetected/reactor.py +0 -1
  62. seleniumbase/undetected/webelement.py +16 -3
  63. {seleniumbase-4.24.10.dist-info → seleniumbase-4.33.15.dist-info}/LICENSE +1 -1
  64. {seleniumbase-4.24.10.dist-info → seleniumbase-4.33.15.dist-info}/METADATA +299 -252
  65. {seleniumbase-4.24.10.dist-info → seleniumbase-4.33.15.dist-info}/RECORD +68 -70
  66. {seleniumbase-4.24.10.dist-info → seleniumbase-4.33.15.dist-info}/WHEEL +1 -1
  67. sbase/ReadMe.txt +0 -2
  68. seleniumbase/ReadMe.md +0 -25
  69. seleniumbase/common/ReadMe.md +0 -71
  70. seleniumbase/console_scripts/ReadMe.md +0 -731
  71. seleniumbase/drivers/ReadMe.md +0 -27
  72. seleniumbase/extensions/ReadMe.md +0 -12
  73. seleniumbase/masterqa/ReadMe.md +0 -61
  74. seleniumbase/resources/ReadMe.md +0 -31
  75. seleniumbase/resources/favicon.ico +0 -0
  76. seleniumbase/utilities/selenium_grid/ReadMe.md +0 -84
  77. seleniumbase/utilities/selenium_ide/ReadMe.md +0 -111
  78. {seleniumbase-4.24.10.dist-info → seleniumbase-4.33.15.dist-info}/entry_points.txt +0 -0
  79. {seleniumbase-4.24.10.dist-info → seleniumbase-4.33.15.dist-info}/top_level.txt +0 -0
@@ -9,8 +9,11 @@ import time
9
9
  import types
10
10
  import urllib3
11
11
  import warnings
12
+ from contextlib import suppress
12
13
  from selenium import webdriver
13
14
  from selenium.common.exceptions import ElementClickInterceptedException
15
+ from selenium.common.exceptions import InvalidSessionIdException
16
+ from selenium.common.exceptions import SessionNotCreatedException
14
17
  from selenium.webdriver.chrome.service import Service as ChromeService
15
18
  from selenium.webdriver.common.options import ArgOptions
16
19
  from selenium.webdriver.common.service import utils as service_utils
@@ -26,7 +29,10 @@ from seleniumbase.core import detect_b_ver
26
29
  from seleniumbase.core import download_helper
27
30
  from seleniumbase.core import proxy_helper
28
31
  from seleniumbase.core import sb_driver
32
+ from seleniumbase.core import sb_cdp
29
33
  from seleniumbase.fixtures import constants
34
+ from seleniumbase.fixtures import js_utils
35
+ from seleniumbase.fixtures import page_actions
30
36
  from seleniumbase.fixtures import shared_utils
31
37
 
32
38
  urllib3.disable_warnings()
@@ -91,19 +97,12 @@ def log_d(message):
91
97
  print(message)
92
98
 
93
99
 
94
- def make_executable(file_path):
95
- # Set permissions to: "If you can read it, you can execute it."
96
- mode = os.stat(file_path).st_mode
97
- mode |= (mode & 0o444) >> 2 # copy R bits to X
98
- os.chmod(file_path, mode)
99
-
100
-
101
100
  def make_driver_executable_if_not(driver_path):
102
101
  # Verify driver has executable permissions. If not, add them.
103
102
  permissions = oct(os.stat(driver_path)[0])[-3:]
104
103
  if "4" in permissions or "6" in permissions:
105
104
  # We want at least a '5' or '7' to make sure it's executable
106
- make_executable(driver_path)
105
+ shared_utils.make_executable(driver_path)
107
106
 
108
107
 
109
108
  def extend_driver(driver):
@@ -129,9 +128,13 @@ def extend_driver(driver):
129
128
  page.assert_element_not_visible = DM.assert_element_not_visible
130
129
  page.assert_text = DM.assert_text
131
130
  page.assert_exact_text = DM.assert_exact_text
131
+ page.assert_non_empty_text = DM.assert_non_empty_text
132
+ page.assert_text_not_visible = DM.assert_text_not_visible
132
133
  page.wait_for_element = DM.wait_for_element
133
134
  page.wait_for_text = DM.wait_for_text
134
135
  page.wait_for_exact_text = DM.wait_for_exact_text
136
+ page.wait_for_non_empty_text = DM.wait_for_non_empty_text
137
+ page.wait_for_text_not_visible = DM.wait_for_text_not_visible
135
138
  page.wait_for_and_accept_alert = DM.wait_for_and_accept_alert
136
139
  page.wait_for_and_dismiss_alert = DM.wait_for_and_dismiss_alert
137
140
  page.is_element_present = DM.is_element_present
@@ -139,12 +142,22 @@ def extend_driver(driver):
139
142
  page.is_text_visible = DM.is_text_visible
140
143
  page.is_exact_text_visible = DM.is_exact_text_visible
141
144
  page.is_attribute_present = DM.is_attribute_present
145
+ page.is_non_empty_text_visible = DM.is_non_empty_text_visible
142
146
  page.get_text = DM.get_text
143
147
  page.find_element = DM.find_element
144
148
  page.find_elements = DM.find_elements
145
149
  page.locator = DM.locator
150
+ page.get_current_url = DM.get_current_url
146
151
  page.get_page_source = DM.get_page_source
147
152
  page.get_title = DM.get_title
153
+ page.get_page_title = DM.get_title
154
+ page.switch_to_default_window = DM.switch_to_default_window
155
+ page.switch_to_newest_window = DM.switch_to_newest_window
156
+ page.open_new_window = DM.open_new_window
157
+ page.open_new_tab = DM.open_new_tab
158
+ page.switch_to_window = DM.switch_to_window
159
+ page.switch_to_tab = DM.switch_to_tab
160
+ page.switch_to_frame = DM.switch_to_frame
148
161
  driver.page = page
149
162
  js = types.SimpleNamespace()
150
163
  js.js_click = DM.js_click
@@ -168,12 +181,16 @@ def extend_driver(driver):
168
181
  driver.assert_element_not_visible = DM.assert_element_not_visible
169
182
  driver.assert_text = DM.assert_text
170
183
  driver.assert_exact_text = DM.assert_exact_text
184
+ driver.assert_non_empty_text = DM.assert_non_empty_text
185
+ driver.assert_text_not_visible = DM.assert_text_not_visible
171
186
  driver.wait_for_element = DM.wait_for_element
172
187
  driver.wait_for_element_visible = DM.wait_for_element_visible
173
188
  driver.wait_for_element_present = DM.wait_for_element_present
174
189
  driver.wait_for_selector = DM.wait_for_selector
175
190
  driver.wait_for_text = DM.wait_for_text
176
191
  driver.wait_for_exact_text = DM.wait_for_exact_text
192
+ driver.wait_for_non_empty_text = DM.wait_for_non_empty_text
193
+ driver.wait_for_text_not_visible = DM.wait_for_text_not_visible
177
194
  driver.wait_for_and_accept_alert = DM.wait_for_and_accept_alert
178
195
  driver.wait_for_and_dismiss_alert = DM.wait_for_and_dismiss_alert
179
196
  driver.is_element_present = DM.is_element_present
@@ -181,20 +198,38 @@ def extend_driver(driver):
181
198
  driver.is_text_visible = DM.is_text_visible
182
199
  driver.is_exact_text_visible = DM.is_exact_text_visible
183
200
  driver.is_attribute_present = DM.is_attribute_present
184
- driver.get_text = DM.get_text
201
+ driver.is_non_empty_text_visible = DM.is_non_empty_text_visible
202
+ driver.is_valid_url = DM.is_valid_url
203
+ driver.is_alert_present = DM.is_alert_present
204
+ driver.is_online = DM.is_online
205
+ driver.is_connected = DM.is_connected
206
+ driver.is_uc_mode_active = DM.is_uc_mode_active
207
+ driver.is_cdp_mode_active = DM.is_cdp_mode_active
185
208
  driver.js_click = DM.js_click
209
+ driver.get_text = DM.get_text
186
210
  driver.get_active_element_css = DM.get_active_element_css
187
211
  driver.get_locale_code = DM.get_locale_code
212
+ driver.get_screen_rect = DM.get_screen_rect
188
213
  driver.get_origin = DM.get_origin
189
214
  driver.get_user_agent = DM.get_user_agent
215
+ driver.get_cookie_string = DM.get_cookie_string
190
216
  driver.highlight = DM.highlight
191
217
  driver.highlight_click = DM.highlight_click
192
218
  driver.highlight_if_visible = DM.highlight_if_visible
193
219
  driver.sleep = time.sleep
194
220
  driver.get_attribute = DM.get_attribute
221
+ driver.get_current_url = DM.get_current_url
195
222
  driver.get_page_source = DM.get_page_source
196
223
  driver.get_title = DM.get_title
224
+ driver.get_page_title = DM.get_title
225
+ driver.switch_to_default_window = DM.switch_to_default_window
226
+ driver.switch_to_newest_window = DM.switch_to_newest_window
227
+ driver.open_new_window = DM.open_new_window
228
+ driver.open_new_tab = DM.open_new_tab
229
+ driver.switch_to_window = DM.switch_to_window
230
+ driver.switch_to_tab = DM.switch_to_tab
197
231
  driver.switch_to_frame = DM.switch_to_frame
232
+ driver.reset_window_size = DM.reset_window_size
198
233
  if hasattr(driver, "proxy"):
199
234
  driver.set_wire_proxy = DM.set_wire_proxy
200
235
  return driver
@@ -249,7 +284,7 @@ def chromedriver_on_path():
249
284
  def get_uc_driver_version(full=False):
250
285
  uc_driver_version = None
251
286
  if os.path.exists(LOCAL_UC_DRIVER):
252
- try:
287
+ with suppress(Exception):
253
288
  output = subprocess.check_output(
254
289
  '"%s" --version' % LOCAL_UC_DRIVER, shell=True
255
290
  )
@@ -264,8 +299,6 @@ def get_uc_driver_version(full=False):
264
299
  uc_driver_version = full_version
265
300
  else:
266
301
  uc_driver_version = output
267
- except Exception:
268
- pass
269
302
  return uc_driver_version
270
303
 
271
304
 
@@ -312,17 +345,19 @@ def find_edgedriver_version_to_use(use_version, driver_version):
312
345
  return use_version
313
346
 
314
347
 
315
- def has_cf(text):
348
+ def has_captcha(text):
316
349
  if (
317
350
  "<title>403 Forbidden</title>" in text
318
351
  or "Permission Denied</title>" in text
319
352
  or 'id="challenge-error-text"' in text
320
353
  or "<title>Just a moment..." in text
321
354
  or 'action="/?__cf_chl_f_tk' in text
355
+ or 'id="challenge-widget-' in text
322
356
  or 'src="chromedriver.js"' in text
323
357
  or 'class="g-recaptcha"' in text
324
358
  or 'content="Pixelscan"' in text
325
359
  or 'id="challenge-form"' in text
360
+ or "/challenge-platform" in text
326
361
  or "window._cf_chl_opt" in text
327
362
  or "/recaptcha/api.js" in text
328
363
  or "/turnstile/" in text
@@ -331,6 +366,11 @@ def has_cf(text):
331
366
  return False
332
367
 
333
368
 
369
+ def __is_cdp_swap_needed(driver):
370
+ """If the driver is disconnected, use a CDP method when available."""
371
+ return shared_utils.is_cdp_swap_needed(driver)
372
+
373
+
334
374
  def uc_special_open_if_cf(
335
375
  driver,
336
376
  url,
@@ -342,32 +382,32 @@ def uc_special_open_if_cf(
342
382
  ):
343
383
  if url.startswith("http:") or url.startswith("https:"):
344
384
  special = False
345
- try:
385
+ with suppress(Exception):
346
386
  req_get = requests_get(url, proxy_string)
347
387
  status_str = str(req_get.status_code)
348
388
  if (
349
389
  status_str.startswith("3")
350
390
  or status_str.startswith("4")
351
391
  or status_str.startswith("5")
352
- or has_cf(req_get.text)
392
+ or has_captcha(req_get.text)
353
393
  ):
354
394
  special = True
355
395
  if status_str == "403" or status_str == "429":
356
396
  time.sleep(0.06) # Forbidden / Blocked! (Wait first!)
357
- except Exception:
358
- pass
359
397
  if special:
360
398
  time.sleep(0.05)
361
399
  with driver:
362
400
  driver.execute_script('window.open("%s","_blank");' % url)
363
401
  driver.close()
364
402
  if mobile_emulator:
365
- driver.switch_to.window(driver.window_handles[-1])
403
+ page_actions.switch_to_window(
404
+ driver, driver.window_handles[-1], 2
405
+ )
366
406
  uc_metrics = {}
367
407
  if (
368
408
  isinstance(device_width, int)
369
409
  and isinstance(device_height, int)
370
- and isinstance(device_pixel_ratio, int)
410
+ and isinstance(device_pixel_ratio, (int, float))
371
411
  ):
372
412
  uc_metrics["width"] = device_width
373
413
  uc_metrics["height"] = device_height
@@ -384,15 +424,15 @@ def uc_special_open_if_cf(
384
424
  "mobile": True
385
425
  }
386
426
  )
387
- try:
427
+ with suppress(Exception):
388
428
  driver.execute_cdp_cmd(
389
429
  'Emulation.setDeviceMetricsOverride',
390
430
  set_device_metrics_override
391
431
  )
392
- except Exception:
393
- pass
394
432
  if not mobile_emulator:
395
- driver.switch_to.window(driver.window_handles[-1])
433
+ page_actions.switch_to_window(
434
+ driver, driver.window_handles[-1], 2
435
+ )
396
436
  else:
397
437
  driver.default_get(url) # The original one
398
438
  else:
@@ -401,30 +441,31 @@ def uc_special_open_if_cf(
401
441
 
402
442
 
403
443
  def uc_open(driver, url):
404
- if url.startswith("//"):
405
- url = "https:" + url
406
- elif ":" not in url:
407
- url = "https://" + url
444
+ url = shared_utils.fix_url_as_needed(url)
445
+ if __is_cdp_swap_needed(driver):
446
+ driver.cdp.get(url)
447
+ time.sleep(0.3)
448
+ return
408
449
  if (url.startswith("http:") or url.startswith("https:")):
409
- time.sleep(0.05)
410
450
  with driver:
411
- driver.default_get(url)
451
+ script = 'window.location.href = "%s";' % url
452
+ js_utils.call_me_later(driver, script, 5)
412
453
  else:
413
454
  driver.default_get(url) # The original one
414
455
  return None
415
456
 
416
457
 
417
458
  def uc_open_with_tab(driver, url):
418
- if url.startswith("//"):
419
- url = "https:" + url
420
- elif ":" not in url:
421
- url = "https://" + url
459
+ url = shared_utils.fix_url_as_needed(url)
460
+ if __is_cdp_swap_needed(driver):
461
+ driver.cdp.get(url)
462
+ time.sleep(0.3)
463
+ return
422
464
  if (url.startswith("http:") or url.startswith("https:")):
423
- time.sleep(0.05)
424
465
  with driver:
425
466
  driver.execute_script('window.open("%s","_blank");' % url)
426
467
  driver.close()
427
- driver.switch_to.window(driver.window_handles[-1])
468
+ page_actions.switch_to_window(driver, driver.window_handles[-1], 2)
428
469
  else:
429
470
  driver.default_get(url) # The original one
430
471
  return None
@@ -432,17 +473,314 @@ def uc_open_with_tab(driver, url):
432
473
 
433
474
  def uc_open_with_reconnect(driver, url, reconnect_time=None):
434
475
  """Open a url, disconnect chromedriver, wait, and reconnect."""
476
+ url = shared_utils.fix_url_as_needed(url)
477
+ if __is_cdp_swap_needed(driver):
478
+ driver.cdp.get(url)
479
+ time.sleep(0.3)
480
+ return
435
481
  if not reconnect_time:
436
482
  reconnect_time = constants.UC.RECONNECT_TIME
437
- if url.startswith("//"):
438
- url = "https:" + url
439
- elif ":" not in url:
440
- url = "https://" + url
441
483
  if (url.startswith("http:") or url.startswith("https:")):
442
- driver.execute_script('window.open("%s","_blank");' % url)
484
+ script = 'window.open("%s","_blank");' % url
485
+ driver.execute_script(script)
486
+ time.sleep(0.05)
487
+ driver.close()
488
+ if reconnect_time == "disconnect":
489
+ driver.disconnect()
490
+ time.sleep(0.008)
491
+ else:
492
+ driver.reconnect(reconnect_time)
493
+ time.sleep(0.004)
494
+ try:
495
+ page_actions.switch_to_window(
496
+ driver, driver.window_handles[-1], 2
497
+ )
498
+ except InvalidSessionIdException:
499
+ time.sleep(0.05)
500
+ page_actions.switch_to_window(
501
+ driver, driver.window_handles[-1], 2
502
+ )
503
+ else:
504
+ driver.default_get(url) # The original one
505
+ return None
506
+
507
+
508
+ def uc_open_with_cdp_mode(driver, url=None):
509
+ import asyncio
510
+ from seleniumbase.undetected.cdp_driver import cdp_util
511
+
512
+ current_url = None
513
+ try:
514
+ current_url = driver.current_url
515
+ except Exception:
516
+ driver.connect()
517
+ current_url = driver.current_url
518
+ url_protocol = current_url.split(":")[0]
519
+ if url_protocol not in ["about", "data", "chrome"]:
520
+ script = 'window.open("data:,","_blank");'
521
+ js_utils.call_me_later(driver, script, 3)
522
+ time.sleep(0.012)
523
+ driver.close()
524
+ driver.disconnect()
525
+
526
+ cdp_details = driver._get_cdp_details()
527
+ cdp_host = cdp_details[1].split("://")[1].split(":")[0]
528
+ cdp_port = int(cdp_details[1].split("://")[1].split(":")[1].split("/")[0])
529
+
530
+ url = shared_utils.fix_url_as_needed(url)
531
+ url_protocol = url.split(":")[0]
532
+ safe_url = True
533
+ if url_protocol not in ["about", "data", "chrome"]:
534
+ safe_url = False
535
+
536
+ headless = False
537
+ headed = None
538
+ xvfb = None
539
+ if hasattr(sb_config, "headless"):
540
+ headless = sb_config.headless
541
+ if hasattr(sb_config, "headed"):
542
+ headed = sb_config.headed
543
+ if hasattr(sb_config, "xvfb"):
544
+ xvfb = sb_config.xvfb
545
+
546
+ loop = asyncio.new_event_loop()
547
+ asyncio.set_event_loop(loop)
548
+ driver.cdp_base = loop.run_until_complete(
549
+ cdp_util.start(
550
+ host=cdp_host,
551
+ port=cdp_port,
552
+ headless=headless,
553
+ headed=headed,
554
+ xvfb=xvfb,
555
+ )
556
+ )
557
+ loop.run_until_complete(driver.cdp_base.wait(0))
558
+
559
+ gui_lock = fasteners.InterProcessLock(constants.MultiBrowser.PYAUTOGUILOCK)
560
+
561
+ if (
562
+ "chrome-extension://" in str(driver.cdp_base.main_tab)
563
+ and len(driver.cdp_base.tabs) >= 2
564
+ ):
565
+ with suppress(Exception):
566
+ loop.run_until_complete(driver.cdp_base.main_tab.close())
567
+
568
+ for tab in driver.cdp_base.tabs[-1::-1]:
569
+ if "chrome-extension://" not in str(tab):
570
+ with gui_lock:
571
+ with suppress(Exception):
572
+ shared_utils.make_writable(
573
+ constants.MultiBrowser.PYAUTOGUILOCK
574
+ )
575
+ loop.run_until_complete(tab.activate())
576
+ break
577
+
578
+ page_tab = None
579
+ if "chrome-extension://" not in str(driver.cdp_base.tabs[-1]):
580
+ page_tab = driver.cdp_base.tabs[-1]
581
+ else:
582
+ for tab in driver.cdp_base.tabs:
583
+ if "chrome-extension://" not in str(tab):
584
+ page_tab = tab
585
+ break
586
+ if page_tab:
587
+ loop.run_until_complete(page_tab.aopen())
588
+ with gui_lock:
589
+ with suppress(Exception):
590
+ shared_utils.make_writable(
591
+ constants.MultiBrowser.PYAUTOGUILOCK
592
+ )
593
+ loop.run_until_complete(page_tab.activate())
594
+
595
+ loop.run_until_complete(driver.cdp_base.update_targets())
596
+ page = loop.run_until_complete(driver.cdp_base.get(url))
597
+ with gui_lock:
598
+ with suppress(Exception):
599
+ shared_utils.make_writable(constants.MultiBrowser.PYAUTOGUILOCK)
600
+ loop.run_until_complete(page.activate())
601
+ loop.run_until_complete(page.wait())
602
+ if not safe_url:
603
+ time.sleep(constants.UC.CDP_MODE_OPEN_WAIT)
604
+ if IS_WINDOWS:
605
+ time.sleep(constants.UC.EXTRA_WINDOWS_WAIT)
606
+ else:
607
+ time.sleep(0.012)
608
+ cdp = types.SimpleNamespace()
609
+ CDPM = sb_cdp.CDPMethods(loop, page, driver)
610
+ cdp.get = CDPM.get
611
+ cdp.open = CDPM.open
612
+ cdp.reload = CDPM.reload
613
+ cdp.refresh = CDPM.refresh
614
+ cdp.add_handler = CDPM.add_handler
615
+ cdp.get_event_loop = CDPM.get_event_loop
616
+ cdp.find_element = CDPM.find_element
617
+ cdp.find = CDPM.find_element
618
+ cdp.locator = CDPM.find_element
619
+ cdp.find_element_by_text = CDPM.find_element_by_text
620
+ cdp.find_all = CDPM.find_all
621
+ cdp.find_elements_by_text = CDPM.find_elements_by_text
622
+ cdp.select = CDPM.select
623
+ cdp.select_all = CDPM.select_all
624
+ cdp.find_elements = CDPM.find_elements
625
+ cdp.find_visible_elements = CDPM.find_visible_elements
626
+ cdp.click_nth_element = CDPM.click_nth_element
627
+ cdp.click_nth_visible_element = CDPM.click_nth_visible_element
628
+ cdp.click_link = CDPM.click_link
629
+ cdp.go_back = CDPM.go_back
630
+ cdp.go_forward = CDPM.go_forward
631
+ cdp.get_navigation_history = CDPM.get_navigation_history
632
+ cdp.tile_windows = CDPM.tile_windows
633
+ cdp.get_all_cookies = CDPM.get_all_cookies
634
+ cdp.set_all_cookies = CDPM.set_all_cookies
635
+ cdp.save_cookies = CDPM.save_cookies
636
+ cdp.load_cookies = CDPM.load_cookies
637
+ cdp.clear_cookies = CDPM.clear_cookies
638
+ cdp.sleep = CDPM.sleep
639
+ cdp.bring_active_window_to_front = CDPM.bring_active_window_to_front
640
+ cdp.bring_to_front = CDPM.bring_active_window_to_front
641
+ cdp.get_active_element = CDPM.get_active_element
642
+ cdp.get_active_element_css = CDPM.get_active_element_css
643
+ cdp.click = CDPM.click
644
+ cdp.click_active_element = CDPM.click_active_element
645
+ cdp.click_if_visible = CDPM.click_if_visible
646
+ cdp.click_visible_elements = CDPM.click_visible_elements
647
+ cdp.mouse_click = CDPM.mouse_click
648
+ cdp.remove_element = CDPM.remove_element
649
+ cdp.remove_from_dom = CDPM.remove_from_dom
650
+ cdp.remove_elements = CDPM.remove_elements
651
+ cdp.send_keys = CDPM.send_keys
652
+ cdp.press_keys = CDPM.press_keys
653
+ cdp.type = CDPM.type
654
+ cdp.set_value = CDPM.set_value
655
+ cdp.evaluate = CDPM.evaluate
656
+ cdp.js_dumps = CDPM.js_dumps
657
+ cdp.maximize = CDPM.maximize
658
+ cdp.minimize = CDPM.minimize
659
+ cdp.medimize = CDPM.medimize
660
+ cdp.set_window_rect = CDPM.set_window_rect
661
+ cdp.reset_window_size = CDPM.reset_window_size
662
+ cdp.set_locale = CDPM.set_locale
663
+ cdp.set_attributes = CDPM.set_attributes
664
+ cdp.gui_press_key = CDPM.gui_press_key
665
+ cdp.gui_press_keys = CDPM.gui_press_keys
666
+ cdp.gui_write = CDPM.gui_write
667
+ cdp.gui_click_x_y = CDPM.gui_click_x_y
668
+ cdp.gui_click_element = CDPM.gui_click_element
669
+ cdp.gui_drag_drop_points = CDPM.gui_drag_drop_points
670
+ cdp.gui_drag_and_drop = CDPM.gui_drag_and_drop
671
+ cdp.gui_hover_x_y = CDPM.gui_hover_x_y
672
+ cdp.gui_hover_element = CDPM.gui_hover_element
673
+ cdp.gui_hover_and_click = CDPM.gui_hover_and_click
674
+ cdp.internalize_links = CDPM.internalize_links
675
+ cdp.get_window = CDPM.get_window
676
+ cdp.get_element_attributes = CDPM.get_element_attributes
677
+ cdp.get_element_attribute = CDPM.get_element_attribute
678
+ cdp.get_attribute = CDPM.get_attribute
679
+ cdp.get_element_html = CDPM.get_element_html
680
+ cdp.get_element_rect = CDPM.get_element_rect
681
+ cdp.get_element_size = CDPM.get_element_size
682
+ cdp.get_element_position = CDPM.get_element_position
683
+ cdp.get_gui_element_rect = CDPM.get_gui_element_rect
684
+ cdp.get_gui_element_center = CDPM.get_gui_element_center
685
+ cdp.get_page_source = CDPM.get_page_source
686
+ cdp.get_user_agent = CDPM.get_user_agent
687
+ cdp.get_cookie_string = CDPM.get_cookie_string
688
+ cdp.get_locale_code = CDPM.get_locale_code
689
+ cdp.get_text = CDPM.get_text
690
+ cdp.get_title = CDPM.get_title
691
+ cdp.get_page_title = CDPM.get_title
692
+ cdp.get_current_url = CDPM.get_current_url
693
+ cdp.get_origin = CDPM.get_origin
694
+ cdp.get_nested_element = CDPM.get_nested_element
695
+ cdp.get_document = CDPM.get_document
696
+ cdp.get_flattened_document = CDPM.get_flattened_document
697
+ cdp.get_screen_rect = CDPM.get_screen_rect
698
+ cdp.get_window_rect = CDPM.get_window_rect
699
+ cdp.get_window_size = CDPM.get_window_size
700
+ cdp.nested_click = CDPM.nested_click
701
+ cdp.select_option_by_text = CDPM.select_option_by_text
702
+ cdp.flash = CDPM.flash
703
+ cdp.highlight = CDPM.highlight
704
+ cdp.focus = CDPM.focus
705
+ cdp.highlight_overlay = CDPM.highlight_overlay
706
+ cdp.get_window_position = CDPM.get_window_position
707
+ cdp.check_if_unchecked = CDPM.check_if_unchecked
708
+ cdp.uncheck_if_checked = CDPM.uncheck_if_checked
709
+ cdp.select_if_unselected = CDPM.select_if_unselected
710
+ cdp.unselect_if_selected = CDPM.unselect_if_selected
711
+ cdp.is_checked = CDPM.is_checked
712
+ cdp.is_selected = CDPM.is_selected
713
+ cdp.is_element_present = CDPM.is_element_present
714
+ cdp.is_element_visible = CDPM.is_element_visible
715
+ cdp.wait_for_element_visible = CDPM.wait_for_element_visible
716
+ cdp.assert_element = CDPM.assert_element
717
+ cdp.assert_element_visible = CDPM.assert_element_visible
718
+ cdp.assert_element_present = CDPM.assert_element_present
719
+ cdp.assert_element_absent = CDPM.assert_element_absent
720
+ cdp.assert_element_not_visible = CDPM.assert_element_not_visible
721
+ cdp.assert_element_attribute = CDPM.assert_element_attribute
722
+ cdp.assert_title = CDPM.assert_title
723
+ cdp.assert_title_contains = CDPM.assert_title_contains
724
+ cdp.assert_url = CDPM.assert_url
725
+ cdp.assert_url_contains = CDPM.assert_url_contains
726
+ cdp.assert_text = CDPM.assert_text
727
+ cdp.assert_exact_text = CDPM.assert_exact_text
728
+ cdp.assert_true = CDPM.assert_true
729
+ cdp.assert_false = CDPM.assert_false
730
+ cdp.assert_equal = CDPM.assert_equal
731
+ cdp.assert_not_equal = CDPM.assert_not_equal
732
+ cdp.assert_in = CDPM.assert_in
733
+ cdp.assert_not_in = CDPM.assert_not_in
734
+ cdp.scroll_into_view = CDPM.scroll_into_view
735
+ cdp.scroll_to_y = CDPM.scroll_to_y
736
+ cdp.scroll_to_top = CDPM.scroll_to_top
737
+ cdp.scroll_to_bottom = CDPM.scroll_to_bottom
738
+ cdp.scroll_up = CDPM.scroll_up
739
+ cdp.scroll_down = CDPM.scroll_down
740
+ cdp.save_screenshot = CDPM.save_screenshot
741
+ cdp.page = page # async world
742
+ cdp.driver = driver.cdp_base # async world
743
+ cdp.tab = cdp.page # shortcut (original)
744
+ cdp.browser = driver.cdp_base # shortcut (original)
745
+ cdp.util = cdp_util # shortcut (original)
746
+ core_items = types.SimpleNamespace()
747
+ core_items.browser = cdp.browser
748
+ core_items.tab = cdp.tab
749
+ core_items.util = cdp.util
750
+ cdp.core = core_items
751
+ cdp.loop = cdp.get_event_loop()
752
+ driver.cdp = cdp
753
+ driver._is_using_cdp = True
754
+
755
+
756
+ def uc_activate_cdp_mode(driver, url=None):
757
+ uc_open_with_cdp_mode(driver, url=url)
758
+
759
+
760
+ def uc_open_with_disconnect(driver, url, timeout=None):
761
+ """Open a url and disconnect chromedriver.
762
+ Then waits for the duration of the timeout.
763
+ Note: You can't perform Selenium actions again
764
+ until after you've called driver.connect()."""
765
+ url = shared_utils.fix_url_as_needed(url)
766
+ if __is_cdp_swap_needed(driver):
767
+ driver.cdp.get(url)
768
+ time.sleep(0.3)
769
+ return
770
+ if not driver.is_connected():
771
+ driver.connect()
772
+ if (url.startswith("http:") or url.startswith("https:")):
773
+ script = 'window.open("%s","_blank");' % url
774
+ driver.execute_script(script)
775
+ time.sleep(0.05)
443
776
  driver.close()
444
- driver.reconnect(reconnect_time)
445
- driver.switch_to.window(driver.window_handles[-1])
777
+ driver.disconnect()
778
+ min_timeout = 0.008
779
+ if timeout and not str(timeout).replace(".", "", 1).isdigit():
780
+ timeout = min_timeout
781
+ if not timeout or timeout < min_timeout:
782
+ timeout = min_timeout
783
+ time.sleep(timeout)
446
784
  else:
447
785
  driver.default_get(url) # The original one
448
786
  return None
@@ -455,19 +793,25 @@ def uc_click(
455
793
  timeout=settings.SMALL_TIMEOUT,
456
794
  reconnect_time=None,
457
795
  ):
458
- try:
796
+ if __is_cdp_swap_needed(driver):
797
+ driver.cdp.click(selector)
798
+ return
799
+ with suppress(Exception):
459
800
  rct = float(by) # Add shortcut: driver.uc_click(selector, RCT)
460
801
  if not reconnect_time:
461
802
  reconnect_time = rct
462
803
  by = "css selector"
463
- except Exception:
464
- pass
465
804
  element = driver.wait_for_selector(selector, by=by, timeout=timeout)
466
- if not element.tag_name == "span": # Element must be "visible"
805
+ tag_name = element.tag_name
806
+ if not tag_name == "span" and not tag_name == "input": # Must be "visible"
467
807
  element = driver.wait_for_element(selector, by=by, timeout=timeout)
468
808
  try:
469
809
  element.uc_click(
470
- driver, selector, by=by, reconnect_time=reconnect_time
810
+ driver,
811
+ selector,
812
+ by=by,
813
+ reconnect_time=reconnect_time,
814
+ tag_name=tag_name,
471
815
  )
472
816
  except ElementClickInterceptedException:
473
817
  time.sleep(0.16)
@@ -478,7 +822,801 @@ def uc_click(
478
822
  driver.reconnect(reconnect_time)
479
823
 
480
824
 
481
- def uc_switch_to_frame(driver, frame, reconnect_time=None):
825
+ def verify_pyautogui_has_a_headed_browser(driver):
826
+ """PyAutoGUI requires a headed browser so that it can
827
+ focus on the correct element when performing actions."""
828
+ if hasattr(driver, "_is_hidden") and driver._is_hidden:
829
+ raise Exception(
830
+ "PyAutoGUI can't be used in headless mode!"
831
+ )
832
+
833
+
834
+ def __install_pyautogui_if_missing():
835
+ try:
836
+ import pyautogui
837
+ with suppress(Exception):
838
+ use_pyautogui_ver = constants.PyAutoGUI.VER
839
+ if pyautogui.__version__ != use_pyautogui_ver:
840
+ del pyautogui
841
+ shared_utils.pip_install(
842
+ "pyautogui", version=use_pyautogui_ver
843
+ )
844
+ import pyautogui
845
+ except Exception:
846
+ print("\nPyAutoGUI required! Installing now...")
847
+ shared_utils.pip_install(
848
+ "pyautogui", version=constants.PyAutoGUI.VER
849
+ )
850
+ try:
851
+ import pyautogui
852
+ except Exception:
853
+ if (
854
+ IS_LINUX
855
+ and hasattr(sb_config, "xvfb")
856
+ and hasattr(sb_config, "headed")
857
+ and hasattr(sb_config, "headless")
858
+ and hasattr(sb_config, "headless2")
859
+ and (not sb_config.headed or sb_config.xvfb)
860
+ and not (sb_config.headless or sb_config.headless2)
861
+ ):
862
+ from sbvirtualdisplay import Display
863
+ xvfb_width = 1366
864
+ xvfb_height = 768
865
+ if (
866
+ hasattr(sb_config, "_xvfb_width")
867
+ and sb_config._xvfb_width
868
+ and isinstance(sb_config._xvfb_width, int)
869
+ and hasattr(sb_config, "_xvfb_height")
870
+ and sb_config._xvfb_height
871
+ and isinstance(sb_config._xvfb_height, int)
872
+ ):
873
+ xvfb_width = sb_config._xvfb_width
874
+ xvfb_height = sb_config._xvfb_height
875
+ if xvfb_width < 1024:
876
+ xvfb_width = 1024
877
+ sb_config._xvfb_width = xvfb_width
878
+ if xvfb_height < 768:
879
+ xvfb_height = 768
880
+ sb_config._xvfb_height = xvfb_height
881
+ with suppress(Exception):
882
+ _xvfb_display = Display(
883
+ visible=True,
884
+ size=(xvfb_width, xvfb_height),
885
+ backend="xvfb",
886
+ use_xauth=True,
887
+ )
888
+ _xvfb_display.start()
889
+ sb_config._virtual_display = _xvfb_display
890
+ sb_config.headless_active = True
891
+
892
+
893
+ def install_pyautogui_if_missing(driver):
894
+ verify_pyautogui_has_a_headed_browser(driver)
895
+ pip_find_lock = fasteners.InterProcessLock(
896
+ constants.PipInstall.FINDLOCK
897
+ )
898
+ try:
899
+ with pip_find_lock:
900
+ pass
901
+ except Exception:
902
+ # Since missing permissions, skip the locks
903
+ __install_pyautogui_if_missing()
904
+ return
905
+ with pip_find_lock: # Prevent issues with multiple processes
906
+ with suppress(Exception):
907
+ shared_utils.make_writable(constants.PipInstall.FINDLOCK)
908
+ __install_pyautogui_if_missing()
909
+
910
+
911
+ def get_configured_pyautogui(pyautogui_copy):
912
+ if (
913
+ IS_LINUX
914
+ and hasattr(pyautogui_copy, "_pyautogui_x11")
915
+ and "DISPLAY" in os.environ.keys()
916
+ ):
917
+ if (
918
+ hasattr(sb_config, "_pyautogui_x11_display")
919
+ and sb_config._pyautogui_x11_display
920
+ and hasattr(pyautogui_copy._pyautogui_x11, "_display")
921
+ and (
922
+ sb_config._pyautogui_x11_display
923
+ == pyautogui_copy._pyautogui_x11._display
924
+ )
925
+ ):
926
+ pass
927
+ else:
928
+ import Xlib.display
929
+ pyautogui_copy._pyautogui_x11._display = (
930
+ Xlib.display.Display(os.environ['DISPLAY'])
931
+ )
932
+ sb_config._pyautogui_x11_display = (
933
+ pyautogui_copy._pyautogui_x11._display
934
+ )
935
+ return pyautogui_copy
936
+
937
+
938
+ def uc_gui_press_key(driver, key):
939
+ install_pyautogui_if_missing(driver)
940
+ import pyautogui
941
+ pyautogui = get_configured_pyautogui(pyautogui)
942
+ gui_lock = fasteners.InterProcessLock(
943
+ constants.MultiBrowser.PYAUTOGUILOCK
944
+ )
945
+ with gui_lock:
946
+ pyautogui.press(key)
947
+
948
+
949
+ def uc_gui_press_keys(driver, keys):
950
+ install_pyautogui_if_missing(driver)
951
+ import pyautogui
952
+ pyautogui = get_configured_pyautogui(pyautogui)
953
+ gui_lock = fasteners.InterProcessLock(
954
+ constants.MultiBrowser.PYAUTOGUILOCK
955
+ )
956
+ with gui_lock:
957
+ for key in keys:
958
+ pyautogui.press(key)
959
+
960
+
961
+ def uc_gui_write(driver, text):
962
+ install_pyautogui_if_missing(driver)
963
+ import pyautogui
964
+ pyautogui = get_configured_pyautogui(pyautogui)
965
+ gui_lock = fasteners.InterProcessLock(
966
+ constants.MultiBrowser.PYAUTOGUILOCK
967
+ )
968
+ with gui_lock:
969
+ pyautogui.write(text)
970
+
971
+
972
+ def get_gui_element_position(driver, selector):
973
+ if __is_cdp_swap_needed(driver):
974
+ element_rect = driver.cdp.get_gui_element_rect(selector)
975
+ return (element_rect["x"], element_rect["y"])
976
+ element = driver.wait_for_element_present(selector, timeout=3)
977
+ element_rect = element.rect
978
+ window_rect = driver.get_window_rect()
979
+ window_bottom_y = window_rect["y"] + window_rect["height"]
980
+ viewport_height = driver.execute_script("return window.innerHeight;")
981
+ viewport_x = window_rect["x"] + element_rect["x"]
982
+ viewport_y = window_bottom_y - viewport_height + element_rect["y"]
983
+ y_scroll_offset = driver.execute_script("return window.pageYOffset;")
984
+ viewport_y = viewport_y - y_scroll_offset
985
+ return (viewport_x, viewport_y)
986
+
987
+
988
+ def _uc_gui_click_x_y(driver, x, y, timeframe=0.25, uc_lock=False):
989
+ install_pyautogui_if_missing(driver)
990
+ import pyautogui
991
+ pyautogui = get_configured_pyautogui(pyautogui)
992
+ screen_width, screen_height = pyautogui.size()
993
+ if x < 0 or y < 0 or x > screen_width or y > screen_height:
994
+ raise Exception(
995
+ "PyAutoGUI cannot click on point (%s, %s)"
996
+ " outside screen. (Width: %s, Height: %s)"
997
+ % (x, y, screen_width, screen_height)
998
+ )
999
+ if uc_lock:
1000
+ gui_lock = fasteners.InterProcessLock(
1001
+ constants.MultiBrowser.PYAUTOGUILOCK
1002
+ )
1003
+ with gui_lock: # Prevent issues with multiple processes
1004
+ pyautogui.moveTo(x, y, timeframe, pyautogui.easeOutQuad)
1005
+ if timeframe >= 0.25:
1006
+ time.sleep(0.056) # Wait if moving at human-speed
1007
+ if "--debug" in sys.argv:
1008
+ print(" <DEBUG> pyautogui.click(%s, %s)" % (x, y))
1009
+ pyautogui.click(x=x, y=y)
1010
+ else:
1011
+ # Called from a method where the gui_lock is already active
1012
+ pyautogui.moveTo(x, y, timeframe, pyautogui.easeOutQuad)
1013
+ if timeframe >= 0.25:
1014
+ time.sleep(0.056) # Wait if moving at human-speed
1015
+ if "--debug" in sys.argv:
1016
+ print(" <DEBUG> pyautogui.click(%s, %s)" % (x, y))
1017
+ pyautogui.click(x=x, y=y)
1018
+
1019
+
1020
+ def uc_gui_click_x_y(driver, x, y, timeframe=0.25):
1021
+ gui_lock = fasteners.InterProcessLock(
1022
+ constants.MultiBrowser.PYAUTOGUILOCK
1023
+ )
1024
+ with gui_lock: # Prevent issues with multiple processes
1025
+ install_pyautogui_if_missing(driver)
1026
+ import pyautogui
1027
+ pyautogui = get_configured_pyautogui(pyautogui)
1028
+ connected = True
1029
+ width_ratio = 1.0
1030
+ if IS_WINDOWS:
1031
+ connected = driver.is_connected()
1032
+ if (
1033
+ not connected
1034
+ and (
1035
+ not hasattr(sb_config, "_saved_width_ratio")
1036
+ or not sb_config._saved_width_ratio
1037
+ )
1038
+ and not __is_cdp_swap_needed(driver)
1039
+ ):
1040
+ driver.reconnect(0.1)
1041
+ if IS_WINDOWS and not __is_cdp_swap_needed(driver):
1042
+ window_rect = driver.get_window_rect()
1043
+ width = window_rect["width"]
1044
+ height = window_rect["height"]
1045
+ win_x = window_rect["x"]
1046
+ win_y = window_rect["y"]
1047
+ scr_width = pyautogui.size().width
1048
+ driver.maximize_window()
1049
+ win_width = driver.get_window_size()["width"]
1050
+ width_ratio = round(float(scr_width) / float(win_width), 2) + 0.01
1051
+ if width_ratio < 0.45 or width_ratio > 2.55:
1052
+ width_ratio = 1.01
1053
+ sb_config._saved_width_ratio = width_ratio
1054
+ driver.minimize_window()
1055
+ driver.set_window_rect(win_x, win_y, width, height)
1056
+ elif IS_WINDOWS and __is_cdp_swap_needed(driver):
1057
+ window_rect = driver.cdp.get_window_rect()
1058
+ width = window_rect["width"]
1059
+ height = window_rect["height"]
1060
+ win_x = window_rect["x"]
1061
+ win_y = window_rect["y"]
1062
+ scr_width = pyautogui.size().width
1063
+ driver.cdp.maximize()
1064
+ win_width = driver.cdp.get_window_size()["width"]
1065
+ width_ratio = round(float(scr_width) / float(win_width), 2) + 0.01
1066
+ if width_ratio < 0.45 or width_ratio > 2.55:
1067
+ width_ratio = 1.01
1068
+ sb_config._saved_width_ratio = width_ratio
1069
+ driver.cdp.minimize()
1070
+ driver.cdp.set_window_rect(win_x, win_y, width, height)
1071
+ if IS_WINDOWS:
1072
+ x = x * width_ratio
1073
+ y = y * width_ratio
1074
+ _uc_gui_click_x_y(driver, x, y, timeframe=timeframe, uc_lock=False)
1075
+ return
1076
+ with suppress(Exception):
1077
+ page_actions.switch_to_window(
1078
+ driver, driver.current_window_handle, 2, uc_lock=False
1079
+ )
1080
+ _uc_gui_click_x_y(driver, x, y, timeframe=timeframe, uc_lock=False)
1081
+
1082
+
1083
+ def _on_a_cf_turnstile_page(driver):
1084
+ source = driver.get_page_source()
1085
+ if (
1086
+ 'data-callback="onCaptchaSuccess"' in source
1087
+ or "/challenge-platform/scripts/" in source
1088
+ or 'id="challenge-widget-' in source
1089
+ or "cf-turnstile-" in source
1090
+ ):
1091
+ return True
1092
+ return False
1093
+
1094
+
1095
+ def _on_a_g_recaptcha_page(driver):
1096
+ source = driver.get_page_source()
1097
+ if (
1098
+ 'id="recaptcha-token"' in source
1099
+ or 'title="reCAPTCHA"' in source
1100
+ ):
1101
+ return True
1102
+ return False
1103
+
1104
+
1105
+ def _uc_gui_click_captcha(
1106
+ driver,
1107
+ frame="iframe",
1108
+ retry=False,
1109
+ blind=False,
1110
+ ctype=None,
1111
+ ):
1112
+ cdp_mode_on_at_start = __is_cdp_swap_needed(driver)
1113
+ _on_a_captcha_page = None
1114
+ if ctype == "cf_t":
1115
+ if not _on_a_cf_turnstile_page(driver):
1116
+ return
1117
+ else:
1118
+ _on_a_captcha_page = _on_a_cf_turnstile_page
1119
+ elif ctype == "g_rc":
1120
+ if not _on_a_g_recaptcha_page(driver):
1121
+ return
1122
+ else:
1123
+ _on_a_captcha_page = _on_a_g_recaptcha_page
1124
+ else:
1125
+ if _on_a_g_recaptcha_page(driver):
1126
+ ctype = "g_rc"
1127
+ _on_a_captcha_page = _on_a_g_recaptcha_page
1128
+ elif _on_a_cf_turnstile_page(driver):
1129
+ ctype = "cf_t"
1130
+ _on_a_captcha_page = _on_a_cf_turnstile_page
1131
+ else:
1132
+ return
1133
+ install_pyautogui_if_missing(driver)
1134
+ import pyautogui
1135
+ pyautogui = get_configured_pyautogui(pyautogui)
1136
+ i_x = None
1137
+ i_y = None
1138
+ x = None
1139
+ y = None
1140
+ visible_iframe = True
1141
+ gui_lock = fasteners.InterProcessLock(
1142
+ constants.MultiBrowser.PYAUTOGUILOCK
1143
+ )
1144
+ with gui_lock: # Prevent issues with multiple processes
1145
+ needs_switch = False
1146
+ width_ratio = 1.0
1147
+ is_in_frame = js_utils.is_in_frame(driver)
1148
+ if is_in_frame and driver.is_element_present("#challenge-stage"):
1149
+ driver.switch_to.parent_frame()
1150
+ needs_switch = True
1151
+ is_in_frame = js_utils.is_in_frame(driver)
1152
+ if not is_in_frame:
1153
+ # Make sure the window is on top
1154
+ if __is_cdp_swap_needed(driver):
1155
+ driver.cdp.bring_active_window_to_front()
1156
+ else:
1157
+ page_actions.switch_to_window(
1158
+ driver, driver.current_window_handle, 2, uc_lock=False
1159
+ )
1160
+ if IS_WINDOWS and not __is_cdp_swap_needed(driver):
1161
+ window_rect = driver.get_window_rect()
1162
+ width = window_rect["width"]
1163
+ height = window_rect["height"]
1164
+ win_x = window_rect["x"]
1165
+ win_y = window_rect["y"]
1166
+ scr_width = pyautogui.size().width
1167
+ driver.maximize_window()
1168
+ win_width = driver.get_window_size()["width"]
1169
+ width_ratio = round(float(scr_width) / float(win_width), 2) + 0.01
1170
+ if width_ratio < 0.45 or width_ratio > 2.55:
1171
+ width_ratio = 1.01
1172
+ sb_config._saved_width_ratio = width_ratio
1173
+ driver.minimize_window()
1174
+ driver.set_window_rect(win_x, win_y, width, height)
1175
+ elif IS_WINDOWS and __is_cdp_swap_needed(driver):
1176
+ window_rect = driver.cdp.get_window_rect()
1177
+ width = window_rect["width"]
1178
+ height = window_rect["height"]
1179
+ win_x = window_rect["x"]
1180
+ win_y = window_rect["y"]
1181
+ scr_width = pyautogui.size().width
1182
+ driver.cdp.maximize()
1183
+ win_width = driver.cdp.get_window_size()["width"]
1184
+ width_ratio = round(float(scr_width) / float(win_width), 2) + 0.01
1185
+ if width_ratio < 0.45 or width_ratio > 2.55:
1186
+ width_ratio = 1.01
1187
+ sb_config._saved_width_ratio = width_ratio
1188
+ driver.cdp.minimize()
1189
+ driver.cdp.set_window_rect(win_x, win_y, width, height)
1190
+ if ctype == "cf_t":
1191
+ if (
1192
+ driver.is_element_present(".cf-turnstile-wrapper iframe")
1193
+ or driver.is_element_present(
1194
+ '[data-callback="onCaptchaSuccess"] iframe'
1195
+ )
1196
+ ):
1197
+ pass
1198
+ else:
1199
+ visible_iframe = False
1200
+ if (
1201
+ frame != "iframe"
1202
+ and driver.is_element_present(
1203
+ "%s .cf-turnstile-wrapper" % frame
1204
+ )
1205
+ ):
1206
+ frame = "%s .cf-turnstile-wrapper" % frame
1207
+ elif (
1208
+ frame != "iframe"
1209
+ and driver.is_element_present(
1210
+ '%s [name*="cf-turnstile"]' % frame
1211
+ )
1212
+ and driver.is_element_present("%s div" % frame)
1213
+ ):
1214
+ frame = "%s div" % frame
1215
+ elif (
1216
+ driver.is_element_present('[name*="cf-turnstile-"]')
1217
+ and driver.is_element_present("#challenge-form div > div")
1218
+ ):
1219
+ frame = "#challenge-form div > div"
1220
+ elif (
1221
+ driver.is_element_present('[name*="cf-turnstile-"]')
1222
+ and driver.is_element_present("[class*=spacer] + div div")
1223
+ ):
1224
+ frame = '[class*=spacer] + div div'
1225
+ elif (
1226
+ driver.is_element_present('[name*="cf-turnstile-"]')
1227
+ and driver.is_element_present("div.spacer div")
1228
+ ):
1229
+ frame = "div.spacer div"
1230
+ elif (
1231
+ driver.is_element_present('script[src*="challenges.c"]')
1232
+ and driver.is_element_present(
1233
+ '[data-testid*="challenge-"] div'
1234
+ )
1235
+ ):
1236
+ frame = '[data-testid*="challenge-"] div'
1237
+ elif driver.is_element_present(
1238
+ 'form div:not([class]):has(input[name*="cf-turn"])'
1239
+ ):
1240
+ frame = 'form div:not([class]):has(input[name*="cf-turn"])'
1241
+ elif (
1242
+ driver.is_element_present('[src*="/turnstile/"]')
1243
+ and driver.is_element_present("form div:not(:has(*))")
1244
+ ):
1245
+ frame = "form div:not(:has(*))"
1246
+ elif driver.is_element_present(".cf-turnstile-wrapper"):
1247
+ frame = ".cf-turnstile-wrapper"
1248
+ elif driver.is_element_present(
1249
+ '[data-callback="onCaptchaSuccess"]'
1250
+ ):
1251
+ frame = '[data-callback="onCaptchaSuccess"]'
1252
+ else:
1253
+ return
1254
+ if (
1255
+ driver.is_element_present("form")
1256
+ and (
1257
+ driver.is_element_present('form[class*="center"]')
1258
+ or driver.is_element_present('form[class*="right"]')
1259
+ or driver.is_element_present('form div[class*="center"]')
1260
+ or driver.is_element_present('form div[class*="right"]')
1261
+ )
1262
+ ):
1263
+ script = (
1264
+ """var $elements = document.querySelectorAll(
1265
+ 'form[class], form div[class]');
1266
+ var index = 0, length = $elements.length;
1267
+ for(; index < length; index++){
1268
+ the_class = $elements[index].getAttribute('class');
1269
+ new_class = the_class.replaceAll('center', 'left');
1270
+ new_class = new_class.replaceAll('right', 'left');
1271
+ $elements[index].setAttribute('class', new_class);}"""
1272
+ )
1273
+ if __is_cdp_swap_needed(driver):
1274
+ driver.cdp.evaluate(script)
1275
+ else:
1276
+ driver.execute_script(script)
1277
+ if not is_in_frame or needs_switch:
1278
+ # Currently not in frame (or nested frame outside CF one)
1279
+ try:
1280
+ i_x, i_y = get_gui_element_position(driver, frame)
1281
+ if visible_iframe:
1282
+ driver.switch_to_frame(frame)
1283
+ except Exception:
1284
+ if visible_iframe:
1285
+ if driver.is_element_present("iframe"):
1286
+ i_x, i_y = get_gui_element_position(driver, "iframe")
1287
+ if driver.is_connected():
1288
+ driver.switch_to_frame("iframe")
1289
+ else:
1290
+ return
1291
+ if not i_x or not i_y:
1292
+ return
1293
+ try:
1294
+ if ctype == "g_rc" and not driver.is_connected():
1295
+ x = (i_x + 29) * width_ratio
1296
+ y = (i_y + 35) * width_ratio
1297
+ elif visible_iframe:
1298
+ selector = "span"
1299
+ if ctype == "g_rc":
1300
+ selector = "span.recaptcha-checkbox"
1301
+ if not driver.is_connected():
1302
+ selector = "iframe"
1303
+ element = driver.wait_for_element_present(
1304
+ selector, timeout=2.5
1305
+ )
1306
+ x = i_x + element.rect["x"] + (element.rect["width"] / 2.0)
1307
+ x += 0.5
1308
+ y = i_y + element.rect["y"] + (element.rect["height"] / 2.0)
1309
+ y += 0.5
1310
+ else:
1311
+ x = (i_x + 32) * width_ratio
1312
+ y = (i_y + 32) * width_ratio
1313
+ if driver.is_connected():
1314
+ driver.switch_to.default_content()
1315
+ except Exception:
1316
+ if driver.is_connected():
1317
+ try:
1318
+ driver.switch_to.default_content()
1319
+ except Exception:
1320
+ return
1321
+ if x and y:
1322
+ sb_config._saved_cf_x_y = (x, y)
1323
+ if not __is_cdp_swap_needed(driver):
1324
+ if driver.is_element_present(".footer .clearfix .ray-id"):
1325
+ driver.uc_open_with_disconnect(
1326
+ driver.get_current_url(), 3.8
1327
+ )
1328
+ else:
1329
+ driver.disconnect()
1330
+ with suppress(Exception):
1331
+ _uc_gui_click_x_y(driver, x, y, timeframe=0.32)
1332
+ if __is_cdp_swap_needed(driver):
1333
+ time.sleep(float(constants.UC.RECONNECT_TIME) / 2.0)
1334
+ return
1335
+ reconnect_time = (float(constants.UC.RECONNECT_TIME) / 2.0) + 0.6
1336
+ if IS_LINUX:
1337
+ reconnect_time = constants.UC.RECONNECT_TIME + 0.2
1338
+ if not x or not y:
1339
+ reconnect_time = 1 # Make it quick (it already failed)
1340
+ driver.reconnect(reconnect_time)
1341
+ caught = False
1342
+ if (
1343
+ driver.is_element_present(".footer .clearfix .ray-id")
1344
+ and not driver.is_element_visible("#challenge-success-text")
1345
+ ):
1346
+ blind = True
1347
+ caught = True
1348
+ if blind:
1349
+ retry = True
1350
+ if retry and x and y and (caught or _on_a_captcha_page(driver)):
1351
+ with gui_lock: # Prevent issues with multiple processes
1352
+ # Make sure the window is on top
1353
+ if __is_cdp_swap_needed(driver):
1354
+ driver.cdp.bring_active_window_to_front()
1355
+ else:
1356
+ page_actions.switch_to_window(
1357
+ driver, driver.current_window_handle, 2, uc_lock=False
1358
+ )
1359
+ if driver.is_element_present("iframe"):
1360
+ try:
1361
+ driver.switch_to_frame(frame)
1362
+ except Exception:
1363
+ try:
1364
+ driver.switch_to_frame("iframe")
1365
+ except Exception:
1366
+ return
1367
+ checkbox_success = None
1368
+ if ctype == "cf_t":
1369
+ checkbox_success = "#success-icon"
1370
+ elif ctype == "g_rc":
1371
+ checkbox_success = "span.recaptcha-checkbox-checked"
1372
+ else:
1373
+ return # If this line is reached, ctype wasn't set
1374
+ if driver.is_element_visible("#success-icon"):
1375
+ driver.switch_to.parent_frame(checkbox_success)
1376
+ return
1377
+ if blind:
1378
+ driver.uc_open_with_disconnect(driver.get_current_url(), 3.8)
1379
+ if __is_cdp_swap_needed(driver) and _on_a_captcha_page(driver):
1380
+ _uc_gui_click_x_y(driver, x, y, timeframe=0.32)
1381
+ else:
1382
+ time.sleep(0.1)
1383
+ else:
1384
+ driver.uc_open_with_reconnect(driver.get_current_url(), 3.8)
1385
+ if _on_a_captcha_page(driver):
1386
+ driver.disconnect()
1387
+ _uc_gui_click_x_y(driver, x, y, timeframe=0.32)
1388
+ if not cdp_mode_on_at_start:
1389
+ driver.reconnect(reconnect_time)
1390
+
1391
+
1392
+ def uc_gui_click_captcha(driver, frame="iframe", retry=False, blind=False):
1393
+ _uc_gui_click_captcha(
1394
+ driver,
1395
+ frame=frame,
1396
+ retry=retry,
1397
+ blind=blind,
1398
+ ctype=None,
1399
+ )
1400
+
1401
+
1402
+ def uc_gui_click_rc(driver, frame="iframe", retry=False, blind=False):
1403
+ _uc_gui_click_captcha(
1404
+ driver,
1405
+ frame=frame,
1406
+ retry=retry,
1407
+ blind=blind,
1408
+ ctype="g_rc",
1409
+ )
1410
+
1411
+
1412
+ def uc_gui_click_cf(driver, frame="iframe", retry=False, blind=False):
1413
+ _uc_gui_click_captcha(
1414
+ driver,
1415
+ frame=frame,
1416
+ retry=retry,
1417
+ blind=blind,
1418
+ ctype="cf_t",
1419
+ )
1420
+
1421
+
1422
+ def _uc_gui_handle_captcha_(driver, frame="iframe", ctype=None):
1423
+ if ctype == "cf_t":
1424
+ if not _on_a_cf_turnstile_page(driver):
1425
+ return
1426
+ elif ctype == "g_rc":
1427
+ if not _on_a_g_recaptcha_page(driver):
1428
+ return
1429
+ else:
1430
+ if _on_a_g_recaptcha_page(driver):
1431
+ ctype = "g_rc"
1432
+ elif _on_a_cf_turnstile_page(driver):
1433
+ ctype = "cf_t"
1434
+ else:
1435
+ return
1436
+ if not driver.is_connected() and not __is_cdp_swap_needed(driver):
1437
+ driver.connect()
1438
+ time.sleep(2)
1439
+ install_pyautogui_if_missing(driver)
1440
+ import pyautogui
1441
+ pyautogui = get_configured_pyautogui(pyautogui)
1442
+ visible_iframe = True
1443
+ gui_lock = fasteners.InterProcessLock(
1444
+ constants.MultiBrowser.PYAUTOGUILOCK
1445
+ )
1446
+ with gui_lock: # Prevent issues with multiple processes
1447
+ needs_switch = False
1448
+ if not __is_cdp_swap_needed(driver):
1449
+ is_in_frame = js_utils.is_in_frame(driver)
1450
+ else:
1451
+ is_in_frame = False
1452
+ selector = "#challenge-stage"
1453
+ if ctype == "g_rc":
1454
+ selector = "#recaptcha-token"
1455
+ if is_in_frame and driver.is_element_present(selector):
1456
+ driver.switch_to.parent_frame()
1457
+ needs_switch = True
1458
+ is_in_frame = js_utils.is_in_frame(driver)
1459
+ if not is_in_frame and not __is_cdp_swap_needed(driver):
1460
+ # Make sure the window is on top
1461
+ page_actions.switch_to_window(
1462
+ driver, driver.current_window_handle, 2, uc_lock=False
1463
+ )
1464
+ if IS_WINDOWS and hasattr(pyautogui, "getActiveWindowTitle"):
1465
+ py_a_g_title = pyautogui.getActiveWindowTitle() or ""
1466
+ window_title = driver.get_title()
1467
+ if not py_a_g_title.startswith(window_title):
1468
+ window_rect = driver.get_window_rect()
1469
+ width = window_rect["width"]
1470
+ height = window_rect["height"]
1471
+ win_x = window_rect["x"]
1472
+ win_y = window_rect["y"]
1473
+ driver.minimize_window()
1474
+ driver.set_window_rect(win_x, win_y, width, height)
1475
+ time.sleep(0.33)
1476
+ tab_up_first = False
1477
+ special_form = False
1478
+ if ctype == "cf_t":
1479
+ if (
1480
+ driver.is_element_present(".cf-turnstile-wrapper iframe")
1481
+ or driver.is_element_present(
1482
+ '[data-callback="onCaptchaSuccess"] iframe'
1483
+ )
1484
+ ):
1485
+ pass
1486
+ else:
1487
+ visible_iframe = False
1488
+ if driver.is_element_present(".cf-turnstile-wrapper"):
1489
+ frame = ".cf-turnstile-wrapper"
1490
+ elif driver.is_element_present(
1491
+ '[data-callback="onCaptchaSuccess"]'
1492
+ ):
1493
+ frame = '[data-callback="onCaptchaSuccess"]'
1494
+ elif (
1495
+ driver.is_element_present('[name*="cf-turnstile-"]')
1496
+ and driver.is_element_present("div.spacer div")
1497
+ ):
1498
+ frame = "div.spacer div"
1499
+ elif (
1500
+ driver.is_element_present('script[src*="challenges.c"]')
1501
+ and driver.is_element_present(
1502
+ '[data-testid*="challenge-"] div'
1503
+ )
1504
+ ):
1505
+ frame = '[data-testid*="challenge-"] div'
1506
+ elif driver.is_element_present(
1507
+ 'form div:not([class]):has(input[name*="cf-turn"])'
1508
+ ):
1509
+ frame = 'form div:not([class]):has(input[name*="cf-turn"])'
1510
+ tab_up_first = True
1511
+ special_form = True
1512
+ elif (
1513
+ driver.is_element_present('[src*="/turnstile/"]')
1514
+ and driver.is_element_present("form div:not(:has(*))")
1515
+ ):
1516
+ frame = "form div:not(:has(*))"
1517
+ tab_up_first = True
1518
+ else:
1519
+ return
1520
+ else:
1521
+ if (
1522
+ driver.is_element_present('iframe[title="reCAPTCHA"]')
1523
+ and frame == "iframe"
1524
+ ):
1525
+ frame = 'iframe[title="reCAPTCHA"]'
1526
+ if not __is_cdp_swap_needed(driver):
1527
+ if not is_in_frame or needs_switch:
1528
+ # Currently not in frame (or nested frame outside CF one)
1529
+ try:
1530
+ if visible_iframe or ctype == "g_rc":
1531
+ driver.switch_to_frame(frame)
1532
+ except Exception:
1533
+ if visible_iframe or ctype == "g_rc":
1534
+ if driver.is_element_present("iframe"):
1535
+ driver.switch_to_frame("iframe")
1536
+ else:
1537
+ return
1538
+ try:
1539
+ selector = "div.cf-turnstile"
1540
+ if ctype == "g_rc":
1541
+ selector = "span#recaptcha-anchor"
1542
+ found_checkbox = False
1543
+ if tab_up_first:
1544
+ for i in range(10):
1545
+ pyautogui.hotkey("shift", "tab")
1546
+ time.sleep(0.027)
1547
+ if ctype == "g_rc":
1548
+ if js_utils.get_active_element_css(driver) == "body":
1549
+ break
1550
+ tab_count = 0
1551
+ for i in range(34):
1552
+ pyautogui.press("\t")
1553
+ tab_count += 1
1554
+ time.sleep(0.027)
1555
+ active_element_css = js_utils.get_active_element_css(driver)
1556
+ if (
1557
+ active_element_css.startswith(selector)
1558
+ or active_element_css.endswith(" > div" * 2)
1559
+ or (special_form and active_element_css.endswith(" div"))
1560
+ or (ctype == "g_rc" and "frame[name" in active_element_css)
1561
+ ):
1562
+ found_checkbox = True
1563
+ sb_config._saved_cf_tab_count = tab_count
1564
+ break
1565
+ time.sleep(0.02)
1566
+ if not found_checkbox:
1567
+ return
1568
+ except Exception:
1569
+ try:
1570
+ driver.switch_to.default_content()
1571
+ except Exception:
1572
+ return
1573
+ if (
1574
+ (
1575
+ driver.is_element_present(".footer .clearfix .ray-id")
1576
+ or driver.is_element_present("script[data-cf-beacon]")
1577
+ )
1578
+ and hasattr(sb_config, "_saved_cf_tab_count")
1579
+ and sb_config._saved_cf_tab_count
1580
+ and not __is_cdp_swap_needed(driver)
1581
+ ):
1582
+ driver.uc_open_with_disconnect(driver.current_url, 3.8)
1583
+ with suppress(Exception):
1584
+ for i in range(sb_config._saved_cf_tab_count):
1585
+ pyautogui.press("\t")
1586
+ time.sleep(0.027)
1587
+ pyautogui.press(" ")
1588
+ else:
1589
+ driver.disconnect()
1590
+ pyautogui.press(" ")
1591
+ reconnect_time = (float(constants.UC.RECONNECT_TIME) / 2.0) + 0.6
1592
+ if IS_LINUX:
1593
+ reconnect_time = constants.UC.RECONNECT_TIME + 0.2
1594
+ driver.reconnect(reconnect_time)
1595
+
1596
+
1597
+ def _uc_gui_handle_captcha(driver, frame="iframe", ctype=None):
1598
+ _uc_gui_handle_captcha_(driver, frame=frame, ctype=ctype)
1599
+ if (
1600
+ driver.is_element_present(".footer .clearfix .ray-id")
1601
+ and not driver.is_element_visible("#challenge-success-text")
1602
+ ):
1603
+ driver.uc_open_with_reconnect(driver.current_url, 3.8)
1604
+ _uc_gui_handle_captcha_(driver, frame=frame, ctype=ctype)
1605
+
1606
+
1607
+ def uc_gui_handle_captcha(driver, frame="iframe"):
1608
+ _uc_gui_handle_captcha(driver, frame=frame, ctype=None)
1609
+
1610
+
1611
+ def uc_gui_handle_cf(driver, frame="iframe"):
1612
+ _uc_gui_handle_captcha(driver, frame=frame, ctype="cf_t")
1613
+
1614
+
1615
+ def uc_gui_handle_rc(driver, frame="iframe"):
1616
+ _uc_gui_handle_captcha(driver, frame=frame, ctype="g_rc")
1617
+
1618
+
1619
+ def uc_switch_to_frame(driver, frame="iframe", reconnect_time=None):
482
1620
  from selenium.webdriver.remote.webelement import WebElement
483
1621
  if isinstance(frame, WebElement):
484
1622
  if not reconnect_time:
@@ -654,22 +1792,34 @@ def _add_chrome_proxy_extension(
654
1792
  ):
655
1793
  # Single-threaded
656
1794
  if zip_it:
657
- proxy_helper.create_proxy_ext(
658
- proxy_string, proxy_user, proxy_pass, bypass_list
659
- )
660
- proxy_zip = proxy_helper.PROXY_ZIP_PATH
661
- chrome_options.add_extension(proxy_zip)
1795
+ proxy_zip_lock = fasteners.InterProcessLock(PROXY_ZIP_LOCK)
1796
+ with proxy_zip_lock:
1797
+ proxy_helper.create_proxy_ext(
1798
+ proxy_string, proxy_user, proxy_pass, bypass_list
1799
+ )
1800
+ proxy_zip = proxy_helper.PROXY_ZIP_PATH
1801
+ chrome_options.add_extension(proxy_zip)
662
1802
  else:
663
- proxy_helper.create_proxy_ext(
664
- proxy_string, proxy_user, proxy_pass, bypass_list, zip_it=False
665
- )
666
- proxy_dir_path = proxy_helper.PROXY_DIR_PATH
667
- chrome_options = add_chrome_ext_dir(chrome_options, proxy_dir_path)
1803
+ proxy_dir_lock = fasteners.InterProcessLock(PROXY_DIR_LOCK)
1804
+ with proxy_dir_lock:
1805
+ proxy_helper.create_proxy_ext(
1806
+ proxy_string,
1807
+ proxy_user,
1808
+ proxy_pass,
1809
+ bypass_list,
1810
+ zip_it=False,
1811
+ )
1812
+ proxy_dir_path = proxy_helper.PROXY_DIR_PATH
1813
+ chrome_options = add_chrome_ext_dir(
1814
+ chrome_options, proxy_dir_path
1815
+ )
668
1816
  else:
669
1817
  # Multi-threaded
670
1818
  if zip_it:
671
1819
  proxy_zip_lock = fasteners.InterProcessLock(PROXY_ZIP_LOCK)
672
1820
  with proxy_zip_lock:
1821
+ with suppress(Exception):
1822
+ shared_utils.make_writable(PROXY_ZIP_LOCK)
673
1823
  if multi_proxy:
674
1824
  _set_proxy_filenames()
675
1825
  if not os.path.exists(proxy_helper.PROXY_ZIP_PATH):
@@ -681,6 +1831,8 @@ def _add_chrome_proxy_extension(
681
1831
  else:
682
1832
  proxy_dir_lock = fasteners.InterProcessLock(PROXY_DIR_LOCK)
683
1833
  with proxy_dir_lock:
1834
+ with suppress(Exception):
1835
+ shared_utils.make_writable(PROXY_DIR_LOCK)
684
1836
  if multi_proxy:
685
1837
  _set_proxy_filenames()
686
1838
  if not os.path.exists(proxy_helper.PROXY_DIR_PATH):
@@ -689,7 +1841,7 @@ def _add_chrome_proxy_extension(
689
1841
  proxy_user,
690
1842
  proxy_pass,
691
1843
  bypass_list,
692
- False,
1844
+ zip_it=False,
693
1845
  )
694
1846
  chrome_options = add_chrome_ext_dir(
695
1847
  chrome_options, proxy_helper.PROXY_DIR_PATH
@@ -706,6 +1858,8 @@ def is_using_uc(undetectable, browser_name):
706
1858
  def _unzip_to_new_folder(zip_file, folder):
707
1859
  proxy_dir_lock = fasteners.InterProcessLock(PROXY_DIR_LOCK)
708
1860
  with proxy_dir_lock:
1861
+ with suppress(Exception):
1862
+ shared_utils.make_writable(PROXY_DIR_LOCK)
709
1863
  if not os.path.exists(folder):
710
1864
  import zipfile
711
1865
  zip_ref = zipfile.ZipFile(zip_file, "r")
@@ -765,6 +1919,7 @@ def _set_chrome_options(
765
1919
  multi_proxy,
766
1920
  user_agent,
767
1921
  recorder_ext,
1922
+ disable_cookies,
768
1923
  disable_js,
769
1924
  disable_csp,
770
1925
  enable_ws,
@@ -776,6 +1931,7 @@ def _set_chrome_options(
776
1931
  log_cdp_events,
777
1932
  no_sandbox,
778
1933
  disable_gpu,
1934
+ headless1,
779
1935
  headless2,
780
1936
  incognito,
781
1937
  guest_mode,
@@ -812,11 +1968,12 @@ def _set_chrome_options(
812
1968
  chrome_options = webdriver.edge.options.Options()
813
1969
  prefs = {}
814
1970
  prefs["download.default_directory"] = downloads_path
815
- prefs["local_discovery.notifications_enabled"] = False
816
- prefs["credentials_enable_service"] = False
817
- prefs["download.prompt_for_download"] = False
818
1971
  prefs["download.directory_upgrade"] = True
819
- prefs["safebrowsing.enabled"] = False
1972
+ prefs["download.prompt_for_download"] = False
1973
+ prefs["credentials_enable_service"] = False
1974
+ prefs["local_discovery.notifications_enabled"] = False
1975
+ prefs["safebrowsing.enabled"] = False # Prevent PW "data breach" pop-ups
1976
+ prefs["safebrowsing.disable_download_protection"] = True
820
1977
  prefs["omnibox-max-zero-suggest-matches"] = 0
821
1978
  prefs["omnibox-use-existing-autocomplete-client"] = 0
822
1979
  prefs["omnibox-trending-zero-prefix-suggestions-on-ntp"] = 0
@@ -827,12 +1984,12 @@ def _set_chrome_options(
827
1984
  prefs["omnibox-zero-suggest-prefetching-on-srp"] = 0
828
1985
  prefs["omnibox-zero-suggest-prefetching-on-web"] = 0
829
1986
  prefs["omnibox-zero-suggest-in-memory-caching"] = 0
830
- prefs["default_content_setting_values.notifications"] = 0
831
1987
  prefs["content_settings.exceptions.automatic_downloads.*.setting"] = 1
832
- prefs["safebrowsing.disable_download_protection"] = True
1988
+ prefs["default_content_setting_values.notifications"] = 0
833
1989
  prefs["default_content_settings.popups"] = 0
834
1990
  prefs["managed_default_content_settings.popups"] = 0
835
1991
  prefs["profile.password_manager_enabled"] = False
1992
+ prefs["profile.password_manager_leak_detection"] = False
836
1993
  prefs["profile.default_content_setting_values.notifications"] = 2
837
1994
  prefs["profile.default_content_settings.popups"] = 0
838
1995
  prefs["profile.managed_default_content_settings.popups"] = 0
@@ -841,6 +1998,8 @@ def _set_chrome_options(
841
1998
  prefs["intl.accept_languages"] = locale_code
842
1999
  if block_images:
843
2000
  prefs["profile.managed_default_content_settings.images"] = 2
2001
+ if disable_cookies:
2002
+ prefs["profile.default_content_setting_values.cookies"] = 2
844
2003
  if disable_js:
845
2004
  prefs["profile.managed_default_content_settings.javascript"] = 2
846
2005
  if do_not_track:
@@ -878,7 +2037,7 @@ def _set_chrome_options(
878
2037
  if (
879
2038
  isinstance(device_width, int)
880
2039
  and isinstance(device_height, int)
881
- and isinstance(device_pixel_ratio, int)
2040
+ and isinstance(device_pixel_ratio, (int, float))
882
2041
  ):
883
2042
  device_metrics["width"] = device_width
884
2043
  device_metrics["height"] = device_height
@@ -893,18 +2052,49 @@ def _set_chrome_options(
893
2052
  chrome_options.add_experimental_option(
894
2053
  "mobileEmulation", emulator_settings
895
2054
  )
2055
+ # Handle Window Position
2056
+ if (headless or headless2) and IS_WINDOWS:
2057
+ # https://stackoverflow.com/a/78999088/7058266
2058
+ chrome_options.add_argument("--window-position=-2400,-2400")
2059
+ else:
2060
+ if (
2061
+ hasattr(settings, "WINDOW_START_X")
2062
+ and isinstance(settings.WINDOW_START_X, int)
2063
+ and hasattr(settings, "WINDOW_START_Y")
2064
+ and isinstance(settings.WINDOW_START_Y, int)
2065
+ ):
2066
+ chrome_options.add_argument(
2067
+ "--window-position=%s,%s" % (
2068
+ settings.WINDOW_START_X, settings.WINDOW_START_Y
2069
+ )
2070
+ )
2071
+ # Handle Window Size
896
2072
  if headless or headless2:
897
- chrome_options.add_argument(
898
- "--window-size=%s,%s" % (
899
- settings.HEADLESS_START_WIDTH, settings.HEADLESS_START_HEIGHT
2073
+ if (
2074
+ hasattr(settings, "HEADLESS_START_WIDTH")
2075
+ and isinstance(settings.HEADLESS_START_WIDTH, int)
2076
+ and hasattr(settings, "HEADLESS_START_HEIGHT")
2077
+ and isinstance(settings.HEADLESS_START_HEIGHT, int)
2078
+ ):
2079
+ chrome_options.add_argument(
2080
+ "--window-size=%s,%s" % (
2081
+ settings.HEADLESS_START_WIDTH,
2082
+ settings.HEADLESS_START_HEIGHT,
2083
+ )
900
2084
  )
901
- )
902
2085
  else:
903
- chrome_options.add_argument(
904
- "--window-size=%s,%s" % (
905
- settings.CHROME_START_WIDTH, settings.CHROME_START_HEIGHT
2086
+ if (
2087
+ hasattr(settings, "CHROME_START_WIDTH")
2088
+ and isinstance(settings.CHROME_START_WIDTH, int)
2089
+ and hasattr(settings, "CHROME_START_HEIGHT")
2090
+ and isinstance(settings.CHROME_START_HEIGHT, int)
2091
+ ):
2092
+ chrome_options.add_argument(
2093
+ "--window-size=%s,%s" % (
2094
+ settings.CHROME_START_WIDTH,
2095
+ settings.CHROME_START_HEIGHT,
2096
+ )
906
2097
  )
907
- )
908
2098
  if (
909
2099
  not proxy_auth
910
2100
  and not disable_csp
@@ -963,7 +2153,10 @@ def _set_chrome_options(
963
2153
  pass # Processed After Version Check
964
2154
  elif headless:
965
2155
  if not undetectable:
966
- chrome_options.add_argument("--headless")
2156
+ if headless1:
2157
+ chrome_options.add_argument("--headless=old")
2158
+ else:
2159
+ chrome_options.add_argument("--headless")
967
2160
  if undetectable and servername and servername != "localhost":
968
2161
  # The Grid Node will need Chrome 109 or newer
969
2162
  chrome_options.add_argument("--headless=new")
@@ -1045,7 +2238,10 @@ def _set_chrome_options(
1045
2238
  chrome_options.add_argument("--ignore-certificate-errors")
1046
2239
  if not enable_ws:
1047
2240
  chrome_options.add_argument("--disable-web-security")
1048
- if IS_LINUX or not is_using_uc(undetectable, browser_name):
2241
+ if (
2242
+ IS_LINUX
2243
+ or (IS_MAC and not is_using_uc(undetectable, browser_name))
2244
+ ):
1049
2245
  chrome_options.add_argument("--no-sandbox")
1050
2246
  if remote_debug:
1051
2247
  # To access the Debugger, go to: chrome://inspect/#devices
@@ -1077,10 +2273,18 @@ def _set_chrome_options(
1077
2273
  binary_loc = detect_b_ver.get_binary_location(br_app, True)
1078
2274
  if os.path.exists(binary_loc):
1079
2275
  binary_location = binary_loc
2276
+ elif os.path.exists("/usr/bin/google-chrome-stable"):
2277
+ binary_location = "/usr/bin/google-chrome-stable"
2278
+ elif os.path.exists("/usr/bin/google-chrome"):
2279
+ binary_location = "/usr/bin/google-chrome"
1080
2280
  extra_disabled_features = []
1081
2281
  if chromium_arg:
1082
- # Can be a comma-separated list of Chromium args
1083
- chromium_arg_list = chromium_arg.split(",")
2282
+ # Can be a comma-separated list of Chromium args or a list
2283
+ chromium_arg_list = None
2284
+ if isinstance(chromium_arg, (list, tuple)):
2285
+ chromium_arg_list = chromium_arg
2286
+ else:
2287
+ chromium_arg_list = chromium_arg.split(",")
1084
2288
  for chromium_arg_item in chromium_arg_list:
1085
2289
  chromium_arg_item = chromium_arg_item.strip()
1086
2290
  if not chromium_arg_item.startswith("--"):
@@ -1089,13 +2293,11 @@ def _set_chrome_options(
1089
2293
  else:
1090
2294
  chromium_arg_item = "--" + chromium_arg_item
1091
2295
  if "remote-debugging-port=" in chromium_arg_item:
1092
- try:
2296
+ with suppress(Exception):
1093
2297
  # Extra processing for UC Mode
1094
2298
  chrome_options._remote_debugging_port = int(
1095
2299
  chromium_arg_item.split("remote-debugging-port=")[1]
1096
2300
  )
1097
- except Exception:
1098
- pass
1099
2301
  if "set-binary" in chromium_arg_item and not binary_location:
1100
2302
  br_app = "google-chrome"
1101
2303
  binary_loc = detect_b_ver.get_binary_location(
@@ -1114,6 +2316,8 @@ def _set_chrome_options(
1114
2316
  chrome_options.add_argument("--auto-open-devtools-for-tabs")
1115
2317
  if user_agent:
1116
2318
  chrome_options.add_argument("--user-agent=%s" % user_agent)
2319
+ chrome_options.add_argument("--safebrowsing-disable-download-protection")
2320
+ chrome_options.add_argument("--disable-search-engine-choice-screen")
1117
2321
  chrome_options.add_argument("--disable-browser-side-navigation")
1118
2322
  chrome_options.add_argument("--disable-save-password-bubble")
1119
2323
  chrome_options.add_argument("--disable-single-click-autofill")
@@ -1134,30 +2338,31 @@ def _set_chrome_options(
1134
2338
  chrome_options.add_argument("--ash-no-nudges")
1135
2339
  chrome_options.add_argument("--no-crash-upload")
1136
2340
  chrome_options.add_argument("--deny-permission-prompts")
2341
+ chrome_options.add_argument(
2342
+ '--simulate-outdated-no-au="Tue, 31 Dec 2099 23:59:59 GMT"'
2343
+ )
2344
+ chrome_options.add_argument("--disable-ipc-flooding-protection")
2345
+ chrome_options.add_argument("--disable-password-generation")
2346
+ chrome_options.add_argument("--disable-domain-reliability")
2347
+ chrome_options.add_argument("--disable-breakpad")
1137
2348
  included_disabled_features = []
1138
- if user_data_dir:
1139
- included_disabled_features.append("OptimizationHintsFetching")
1140
- included_disabled_features.append("Translate")
1141
- included_disabled_features.append("OptimizationTargetPrediction")
1142
- included_disabled_features.append("PrivacySandboxSettings4")
1143
- included_disabled_features.append("DownloadBubble")
1144
- included_disabled_features.append("DownloadBubbleV2")
1145
- for item in extra_disabled_features:
1146
- if item not in included_disabled_features:
1147
- included_disabled_features.append(item)
1148
- d_f_string = ",".join(included_disabled_features)
1149
- chrome_options.add_argument("--disable-features=%s" % d_f_string)
1150
- else:
1151
- included_disabled_features.append("OptimizationHintsFetching")
1152
- included_disabled_features.append("Translate")
1153
- included_disabled_features.append("OptimizationTargetPrediction")
1154
- included_disabled_features.append("DownloadBubble")
1155
- included_disabled_features.append("DownloadBubbleV2")
1156
- for item in extra_disabled_features:
1157
- if item not in included_disabled_features:
1158
- included_disabled_features.append(item)
1159
- d_f_string = ",".join(included_disabled_features)
1160
- chrome_options.add_argument("--disable-features=%s" % d_f_string)
2349
+ included_disabled_features.append("OptimizationHints")
2350
+ included_disabled_features.append("OptimizationHintsFetching")
2351
+ included_disabled_features.append("Translate")
2352
+ included_disabled_features.append("OptimizationTargetPrediction")
2353
+ included_disabled_features.append("OptimizationGuideModelDownloading")
2354
+ included_disabled_features.append("DownloadBubble")
2355
+ included_disabled_features.append("DownloadBubbleV2")
2356
+ included_disabled_features.append("InsecureDownloadWarnings")
2357
+ included_disabled_features.append("InterestFeedContentSuggestions")
2358
+ included_disabled_features.append("PrivacySandboxSettings4")
2359
+ included_disabled_features.append("SidePanelPinning")
2360
+ included_disabled_features.append("UserAgentClientHint")
2361
+ for item in extra_disabled_features:
2362
+ if item not in included_disabled_features:
2363
+ included_disabled_features.append(item)
2364
+ d_f_string = ",".join(included_disabled_features)
2365
+ chrome_options.add_argument("--disable-features=%s" % d_f_string)
1161
2366
  if (
1162
2367
  is_using_uc(undetectable, browser_name)
1163
2368
  and (
@@ -1165,8 +2370,14 @@ def _set_chrome_options(
1165
2370
  or IS_LINUX # switches to Xvfb (non-headless)
1166
2371
  )
1167
2372
  ):
2373
+ chrome_options.add_argument("--no-pings")
2374
+ chrome_options.add_argument("--homepage=chrome://version/")
2375
+ chrome_options.add_argument("--animation-duration-scale=0")
2376
+ chrome_options.add_argument("--wm-window-animations-disabled")
2377
+ chrome_options.add_argument("--enable-privacy-sandbox-ads-apis")
2378
+ chrome_options.add_argument("--disable-background-timer-throttling")
2379
+ # Prevent new tabs opened by Selenium from being blocked:
1168
2380
  chrome_options.add_argument("--disable-popup-blocking")
1169
- chrome_options.add_argument("--homepage=chrome://new-tab-page/")
1170
2381
  # Skip remaining options that trigger anti-bot services
1171
2382
  return chrome_options
1172
2383
  chrome_options.add_argument("--test-type")
@@ -1193,10 +2404,12 @@ def _set_firefox_options(
1193
2404
  proxy_bypass_list,
1194
2405
  proxy_pac_url,
1195
2406
  user_agent,
2407
+ disable_cookies,
1196
2408
  disable_js,
1197
2409
  disable_csp,
1198
2410
  firefox_arg,
1199
2411
  firefox_pref,
2412
+ external_pdf,
1200
2413
  ):
1201
2414
  blank_p = "about:blank"
1202
2415
  options = webdriver.FirefoxOptions()
@@ -1208,7 +2421,6 @@ def _set_firefox_options(
1208
2421
  options.set_preference("browser.newtab.url", blank_p)
1209
2422
  options.set_preference("trailhead.firstrun.branches", "nofirstrun-empty")
1210
2423
  options.set_preference("browser.aboutwelcome.enabled", False)
1211
- options.set_preference("pdfjs.disabled", True)
1212
2424
  options.set_preference("app.update.auto", False)
1213
2425
  options.set_preference("app.update.enabled", False)
1214
2426
  options.set_preference("browser.formfill.enable", False)
@@ -1216,8 +2428,6 @@ def _set_firefox_options(
1216
2428
  options.set_preference("dom.webnotifications.enabled", False)
1217
2429
  options.set_preference("dom.disable_beforeunload", True)
1218
2430
  options.set_preference("browser.contentblocking.database.enabled", True)
1219
- options.set_preference("extensions.allowPrivateBrowsingByDefault", True)
1220
- options.set_preference("extensions.PrivateBrowsing.notification", False)
1221
2431
  options.set_preference("extensions.systemAddon.update.enabled", False)
1222
2432
  options.set_preference("extensions.update.autoUpdateDefault", False)
1223
2433
  options.set_preference("extensions.update.enabled", False)
@@ -1266,6 +2476,8 @@ def _set_firefox_options(
1266
2476
  "security.mixed_content.block_active_content", False
1267
2477
  )
1268
2478
  options.set_preference("security.warn_submit_insecure", False)
2479
+ if disable_cookies:
2480
+ options.set_preference("network.cookie.cookieBehavior", 2)
1269
2481
  if disable_js:
1270
2482
  options.set_preference("javascript.enabled", False)
1271
2483
  if settings.DISABLE_CSP_ON_FIREFOX or disable_csp:
@@ -1293,22 +2505,27 @@ def _set_firefox_options(
1293
2505
  options.set_preference(
1294
2506
  "browser.helperApps.neverAsk.saveToDisk",
1295
2507
  (
1296
- "application/pdf, application/zip, application/octet-stream, "
1297
- "text/csv, text/xml, application/xml, text/plain, "
1298
- "text/octet-stream, application/x-gzip, application/x-tar "
1299
- "application/"
1300
- "vnd.openxmlformats-officedocument.spreadsheetml.sheet"
2508
+ "application/pdf,application/zip,application/octet-stream,"
2509
+ "text/csv,text/xml,application/xml,text/plain,application/json,"
2510
+ "text/octet-stream,application/x-gzip,application/x-tar,"
2511
+ "application/java-archive,text/x-java-source,java,"
2512
+ "application/javascript,video/jpeg,audio/x-aac,image/svg+xml,"
2513
+ "application/x-font-woff,application/x-7z-compressed,"
2514
+ "application/mp4,video/mp4,audio/mp4,video/x-msvideo,"
2515
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
1301
2516
  ),
1302
2517
  )
2518
+ if external_pdf:
2519
+ options.set_preference("pdfjs.disabled", True)
2520
+ else:
2521
+ options.set_preference("pdfjs.disabled", False)
1303
2522
  if firefox_arg:
1304
2523
  # Can be a comma-separated list of Firefox args
1305
2524
  firefox_arg_list = firefox_arg.split(",")
1306
2525
  for firefox_arg_item in firefox_arg_list:
1307
2526
  firefox_arg_item = firefox_arg_item.strip()
1308
- if not firefox_arg_item.startswith("--"):
1309
- if firefox_arg_item.startswith("-"):
1310
- firefox_arg_item = "-" + firefox_arg_item
1311
- else:
2527
+ if not firefox_arg_item.startswith("-"):
2528
+ if firefox_arg_item.count(os.sep) == 0:
1312
2529
  firefox_arg_item = "--" + firefox_arg_item
1313
2530
  if len(firefox_arg_item) >= 3:
1314
2531
  options.add_argument(firefox_arg_item)
@@ -1340,7 +2557,7 @@ def _set_firefox_options(
1340
2557
  f_pref_value = False
1341
2558
  elif f_pref_value.isdigit():
1342
2559
  f_pref_value = int(f_pref_value)
1343
- elif f_pref_value.isdecimal():
2560
+ elif f_pref_value.replace(".", "", 1).isdigit():
1344
2561
  f_pref_value = float(f_pref_value)
1345
2562
  else:
1346
2563
  pass # keep as string
@@ -1365,6 +2582,7 @@ def get_driver(
1365
2582
  cap_file=None,
1366
2583
  cap_string=None,
1367
2584
  recorder_ext=False,
2585
+ disable_cookies=False,
1368
2586
  disable_js=False,
1369
2587
  disable_csp=False,
1370
2588
  enable_ws=False,
@@ -1376,6 +2594,7 @@ def get_driver(
1376
2594
  log_cdp_events=False,
1377
2595
  no_sandbox=False,
1378
2596
  disable_gpu=False,
2597
+ headless1=False,
1379
2598
  headless2=False,
1380
2599
  incognito=False,
1381
2600
  guest_mode=False,
@@ -1524,6 +2743,7 @@ def get_driver(
1524
2743
  headless
1525
2744
  and (
1526
2745
  proxy_auth
2746
+ or disable_cookies
1527
2747
  or disable_js
1528
2748
  or ad_block_on
1529
2749
  or disable_csp
@@ -1578,6 +2798,7 @@ def get_driver(
1578
2798
  cap_file,
1579
2799
  cap_string,
1580
2800
  recorder_ext,
2801
+ disable_cookies,
1581
2802
  disable_js,
1582
2803
  disable_csp,
1583
2804
  enable_ws,
@@ -1589,6 +2810,7 @@ def get_driver(
1589
2810
  log_cdp_events,
1590
2811
  no_sandbox,
1591
2812
  disable_gpu,
2813
+ headless1,
1592
2814
  headless2,
1593
2815
  incognito,
1594
2816
  guest_mode,
@@ -1634,6 +2856,7 @@ def get_driver(
1634
2856
  multi_proxy,
1635
2857
  user_agent,
1636
2858
  recorder_ext,
2859
+ disable_cookies,
1637
2860
  disable_js,
1638
2861
  disable_csp,
1639
2862
  enable_ws,
@@ -1645,6 +2868,7 @@ def get_driver(
1645
2868
  log_cdp_events,
1646
2869
  no_sandbox,
1647
2870
  disable_gpu,
2871
+ headless1,
1648
2872
  headless2,
1649
2873
  incognito,
1650
2874
  guest_mode,
@@ -1694,6 +2918,7 @@ def get_remote_driver(
1694
2918
  cap_file,
1695
2919
  cap_string,
1696
2920
  recorder_ext,
2921
+ disable_cookies,
1697
2922
  disable_js,
1698
2923
  disable_csp,
1699
2924
  enable_ws,
@@ -1705,6 +2930,7 @@ def get_remote_driver(
1705
2930
  log_cdp_events,
1706
2931
  no_sandbox,
1707
2932
  disable_gpu,
2933
+ headless1,
1708
2934
  headless2,
1709
2935
  incognito,
1710
2936
  guest_mode,
@@ -1739,14 +2965,28 @@ def get_remote_driver(
1739
2965
  pip_find_lock = fasteners.InterProcessLock(
1740
2966
  constants.PipInstall.FINDLOCK
1741
2967
  )
1742
- with pip_find_lock:
2968
+ with pip_find_lock: # Prevent issues with multiple processes
2969
+ with suppress(Exception):
2970
+ shared_utils.make_writable(constants.PipInstall.FINDLOCK)
1743
2971
  try:
1744
2972
  from seleniumwire import webdriver
2973
+ import blinker
2974
+ with suppress(Exception):
2975
+ use_blinker_ver = constants.SeleniumWire.BLINKER_VER
2976
+ if blinker.__version__ != use_blinker_ver:
2977
+ shared_utils.pip_install(
2978
+ "blinker", version=use_blinker_ver
2979
+ )
2980
+ del blinker
1745
2981
  except Exception:
2982
+ shared_utils.pip_install(
2983
+ "blinker", version=constants.SeleniumWire.BLINKER_VER
2984
+ )
1746
2985
  shared_utils.pip_install(
1747
2986
  "selenium-wire", version=constants.SeleniumWire.VER
1748
2987
  )
1749
2988
  from seleniumwire import webdriver
2989
+ warnings.simplefilter("ignore", category=DeprecationWarning)
1750
2990
  else:
1751
2991
  from selenium import webdriver
1752
2992
 
@@ -1817,6 +3057,7 @@ def get_remote_driver(
1817
3057
  multi_proxy,
1818
3058
  user_agent,
1819
3059
  recorder_ext,
3060
+ disable_cookies,
1820
3061
  disable_js,
1821
3062
  disable_csp,
1822
3063
  enable_ws,
@@ -1828,6 +3069,7 @@ def get_remote_driver(
1828
3069
  log_cdp_events,
1829
3070
  no_sandbox,
1830
3071
  disable_gpu,
3072
+ headless1,
1831
3073
  headless2,
1832
3074
  incognito,
1833
3075
  guest_mode,
@@ -1911,10 +3153,12 @@ def get_remote_driver(
1911
3153
  proxy_bypass_list,
1912
3154
  proxy_pac_url,
1913
3155
  user_agent,
3156
+ disable_cookies,
1914
3157
  disable_js,
1915
3158
  disable_csp,
1916
3159
  firefox_arg,
1917
3160
  firefox_pref,
3161
+ external_pdf,
1918
3162
  )
1919
3163
  capabilities = webdriver.FirefoxOptions().to_capabilities()
1920
3164
  capabilities["marionette"] = True
@@ -1989,6 +3233,7 @@ def get_remote_driver(
1989
3233
  multi_proxy,
1990
3234
  user_agent,
1991
3235
  recorder_ext,
3236
+ disable_cookies,
1992
3237
  disable_js,
1993
3238
  disable_csp,
1994
3239
  enable_ws,
@@ -2000,6 +3245,7 @@ def get_remote_driver(
2000
3245
  log_cdp_events,
2001
3246
  no_sandbox,
2002
3247
  disable_gpu,
3248
+ headless1,
2003
3249
  headless2,
2004
3250
  incognito,
2005
3251
  guest_mode,
@@ -2108,6 +3354,7 @@ def get_local_driver(
2108
3354
  multi_proxy,
2109
3355
  user_agent,
2110
3356
  recorder_ext,
3357
+ disable_cookies,
2111
3358
  disable_js,
2112
3359
  disable_csp,
2113
3360
  enable_ws,
@@ -2119,6 +3366,7 @@ def get_local_driver(
2119
3366
  log_cdp_events,
2120
3367
  no_sandbox,
2121
3368
  disable_gpu,
3369
+ headless1,
2122
3370
  headless2,
2123
3371
  incognito,
2124
3372
  guest_mode,
@@ -2153,17 +3401,31 @@ def get_local_driver(
2153
3401
  downloads_path = DOWNLOADS_FOLDER
2154
3402
  b_path = binary_location
2155
3403
  if use_wire:
2156
- driver_fixing_lock = fasteners.InterProcessLock(
2157
- constants.MultiBrowser.DRIVER_FIXING_LOCK
3404
+ pip_find_lock = fasteners.InterProcessLock(
3405
+ constants.PipInstall.FINDLOCK
2158
3406
  )
2159
- with driver_fixing_lock: # Prevent multi-processes mode issues
3407
+ with pip_find_lock: # Prevent issues with multiple processes
3408
+ with suppress(Exception):
3409
+ shared_utils.make_writable(constants.PipInstall.FINDLOCK)
2160
3410
  try:
2161
3411
  from seleniumwire import webdriver
3412
+ import blinker
3413
+ with suppress(Exception):
3414
+ use_blinker_ver = constants.SeleniumWire.BLINKER_VER
3415
+ if blinker.__version__ != use_blinker_ver:
3416
+ shared_utils.pip_install(
3417
+ "blinker", version=use_blinker_ver
3418
+ )
3419
+ del blinker
2162
3420
  except Exception:
3421
+ shared_utils.pip_install(
3422
+ "blinker", version=constants.SeleniumWire.BLINKER_VER
3423
+ )
2163
3424
  shared_utils.pip_install(
2164
3425
  "selenium-wire", version=constants.SeleniumWire.VER
2165
3426
  )
2166
3427
  from seleniumwire import webdriver
3428
+ warnings.simplefilter("ignore", category=DeprecationWarning)
2167
3429
  else:
2168
3430
  from selenium import webdriver
2169
3431
 
@@ -2176,10 +3438,12 @@ def get_local_driver(
2176
3438
  proxy_bypass_list,
2177
3439
  proxy_pac_url,
2178
3440
  user_agent,
3441
+ disable_cookies,
2179
3442
  disable_js,
2180
3443
  disable_csp,
2181
3444
  firefox_arg,
2182
3445
  firefox_pref,
3446
+ external_pdf,
2183
3447
  )
2184
3448
  if LOCAL_GECKODRIVER and os.path.exists(LOCAL_GECKODRIVER):
2185
3449
  try:
@@ -2206,6 +3470,10 @@ def get_local_driver(
2206
3470
  constants.MultiBrowser.DRIVER_FIXING_LOCK
2207
3471
  )
2208
3472
  with geckodriver_fixing_lock:
3473
+ with suppress(Exception):
3474
+ shared_utils.make_writable(
3475
+ constants.MultiBrowser.DRIVER_FIXING_LOCK
3476
+ )
2209
3477
  if not geckodriver_on_path():
2210
3478
  sys_args = sys.argv # Save a copy of sys args
2211
3479
  log_d(
@@ -2232,11 +3500,13 @@ def get_local_driver(
2232
3500
  or "Process unexpectedly closed" in str(e)
2233
3501
  or "Failed to read marionette port" in str(e)
2234
3502
  or "A connection attempt failed" in str(e)
3503
+ or "Expected browser binary" in str(e)
2235
3504
  or hasattr(e, "msg") and (
2236
3505
  "geckodriver unexpectedly exited" in e.msg
2237
3506
  or "Process unexpectedly closed" in e.msg
2238
3507
  or "Failed to read marionette port" in e.msg
2239
3508
  or "A connection attempt failed" in e.msg
3509
+ or "Expected browser binary" in e.msg
2240
3510
  )
2241
3511
  ):
2242
3512
  time.sleep(0.1)
@@ -2272,11 +3542,13 @@ def get_local_driver(
2272
3542
  or "Process unexpectedly closed" in str(e)
2273
3543
  or "Failed to read marionette port" in str(e)
2274
3544
  or "A connection attempt failed" in str(e)
3545
+ or "Expected browser binary" in str(e)
2275
3546
  or hasattr(e, "msg") and (
2276
3547
  "geckodriver unexpectedly exited" in e.msg
2277
3548
  or "Process unexpectedly closed" in e.msg
2278
3549
  or "Failed to read marionette port" in e.msg
2279
3550
  or "A connection attempt failed" in e.msg
3551
+ or "Expected browser binary" in e.msg
2280
3552
  )
2281
3553
  ):
2282
3554
  time.sleep(0.1)
@@ -2367,11 +3639,12 @@ def get_local_driver(
2367
3639
  elif browser_name == constants.Browser.EDGE:
2368
3640
  prefs = {
2369
3641
  "download.default_directory": downloads_path,
2370
- "local_discovery.notifications_enabled": False,
2371
- "credentials_enable_service": False,
2372
- "download.prompt_for_download": False,
2373
3642
  "download.directory_upgrade": True,
2374
- "safebrowsing.enabled": False,
3643
+ "download.prompt_for_download": False,
3644
+ "credentials_enable_service": False,
3645
+ "local_discovery.notifications_enabled": False,
3646
+ "safebrowsing.disable_download_protection": True,
3647
+ "safebrowsing.enabled": False, # Prevent PW "data breach" pop-ups
2375
3648
  "omnibox-max-zero-suggest-matches": 0,
2376
3649
  "omnibox-use-existing-autocomplete-client": 0,
2377
3650
  "omnibox-trending-zero-prefix-suggestions-on-ntp": 0,
@@ -2382,12 +3655,12 @@ def get_local_driver(
2382
3655
  "omnibox-zero-suggest-prefetching-on-srp": 0,
2383
3656
  "omnibox-zero-suggest-prefetching-on-web": 0,
2384
3657
  "omnibox-zero-suggest-in-memory-caching": 0,
2385
- "safebrowsing.disable_download_protection": True,
3658
+ "content_settings.exceptions.automatic_downloads.*.setting": 1,
2386
3659
  "default_content_setting_values.notifications": 0,
2387
3660
  "default_content_settings.popups": 0,
2388
3661
  "managed_default_content_settings.popups": 0,
2389
- "content_settings.exceptions.automatic_downloads.*.setting": 1,
2390
3662
  "profile.password_manager_enabled": False,
3663
+ "profile.password_manager_leak_detection": False,
2391
3664
  "profile.default_content_setting_values.notifications": 2,
2392
3665
  "profile.default_content_settings.popups": 0,
2393
3666
  "profile.managed_default_content_settings.popups": 0,
@@ -2440,7 +3713,7 @@ def get_local_driver(
2440
3713
  edge_driver_version = None
2441
3714
  edgedriver_upgrade_needed = False
2442
3715
  if os.path.exists(LOCAL_EDGEDRIVER):
2443
- try:
3716
+ with suppress(Exception):
2444
3717
  output = subprocess.check_output(
2445
3718
  '"%s" --version' % LOCAL_EDGEDRIVER, shell=True
2446
3719
  )
@@ -2466,8 +3739,6 @@ def get_local_driver(
2466
3739
  edge_driver_version = output
2467
3740
  if driver_version == "keep":
2468
3741
  driver_version = edge_driver_version
2469
- except Exception:
2470
- pass
2471
3742
  use_version = find_edgedriver_version_to_use(
2472
3743
  use_version, driver_version
2473
3744
  )
@@ -2505,6 +3776,10 @@ def get_local_driver(
2505
3776
  constants.MultiBrowser.DRIVER_FIXING_LOCK
2506
3777
  )
2507
3778
  with edgedriver_fixing_lock:
3779
+ with suppress(Exception):
3780
+ shared_utils.make_writable(
3781
+ constants.MultiBrowser.DRIVER_FIXING_LOCK
3782
+ )
2508
3783
  msg = "Microsoft Edge Driver not found."
2509
3784
  if edgedriver_upgrade_needed:
2510
3785
  msg = "Microsoft Edge Driver update needed."
@@ -2530,6 +3805,8 @@ def get_local_driver(
2530
3805
  prefs["intl.accept_languages"] = locale_code
2531
3806
  if block_images:
2532
3807
  prefs["profile.managed_default_content_settings.images"] = 2
3808
+ if disable_cookies:
3809
+ prefs["profile.default_content_setting_values.cookies"] = 2
2533
3810
  if disable_js:
2534
3811
  prefs["profile.managed_default_content_settings.javascript"] = 2
2535
3812
  if do_not_track:
@@ -2571,7 +3848,7 @@ def get_local_driver(
2571
3848
  edge_options.add_argument("--headless=new")
2572
3849
  elif headless and undetectable:
2573
3850
  # (For later: UC Mode doesn't support Edge now)
2574
- try:
3851
+ with suppress(Exception):
2575
3852
  if int(use_version) >= 109:
2576
3853
  edge_options.add_argument("--headless=new")
2577
3854
  elif (
@@ -2581,18 +3858,22 @@ def get_local_driver(
2581
3858
  edge_options.add_argument("--headless=chrome")
2582
3859
  else:
2583
3860
  pass # Will need Xvfb on Linux
2584
- except Exception:
2585
- pass
2586
3861
  elif headless:
2587
- if "--headless" not in edge_options.arguments:
2588
- edge_options.add_argument("--headless")
3862
+ if (
3863
+ "--headless" not in edge_options.arguments
3864
+ and "--headless=old" not in edge_options.arguments
3865
+ ):
3866
+ if headless1:
3867
+ edge_options.add_argument("--headless=old")
3868
+ else:
3869
+ edge_options.add_argument("--headless")
2589
3870
  if mobile_emulator and not is_using_uc(undetectable, browser_name):
2590
3871
  emulator_settings = {}
2591
3872
  device_metrics = {}
2592
3873
  if (
2593
3874
  isinstance(device_width, int)
2594
3875
  and isinstance(device_height, int)
2595
- and isinstance(device_pixel_ratio, int)
3876
+ and isinstance(device_pixel_ratio, (int, float))
2596
3877
  ):
2597
3878
  device_metrics["width"] = device_width
2598
3879
  device_metrics["height"] = device_height
@@ -2607,20 +3888,49 @@ def get_local_driver(
2607
3888
  edge_options.add_experimental_option(
2608
3889
  "mobileEmulation", emulator_settings
2609
3890
  )
3891
+ # Handle Window Position
3892
+ if (headless or headless2) and IS_WINDOWS:
3893
+ # https://stackoverflow.com/a/78999088/7058266
3894
+ edge_options.add_argument("--window-position=-2400,-2400")
3895
+ else:
3896
+ if (
3897
+ hasattr(settings, "WINDOW_START_X")
3898
+ and isinstance(settings.WINDOW_START_X, int)
3899
+ and hasattr(settings, "WINDOW_START_Y")
3900
+ and isinstance(settings.WINDOW_START_Y, int)
3901
+ ):
3902
+ edge_options.add_argument(
3903
+ "--window-position=%s,%s" % (
3904
+ settings.WINDOW_START_X, settings.WINDOW_START_Y
3905
+ )
3906
+ )
3907
+ # Handle Window Size
2610
3908
  if headless or headless2:
2611
- edge_options.add_argument(
2612
- "--window-size=%s,%s" % (
2613
- settings.HEADLESS_START_WIDTH,
2614
- settings.HEADLESS_START_HEIGHT,
3909
+ if (
3910
+ hasattr(settings, "HEADLESS_START_WIDTH")
3911
+ and isinstance(settings.HEADLESS_START_WIDTH, int)
3912
+ and hasattr(settings, "HEADLESS_START_HEIGHT")
3913
+ and isinstance(settings.HEADLESS_START_HEIGHT, int)
3914
+ ):
3915
+ edge_options.add_argument(
3916
+ "--window-size=%s,%s" % (
3917
+ settings.HEADLESS_START_WIDTH,
3918
+ settings.HEADLESS_START_HEIGHT,
3919
+ )
2615
3920
  )
2616
- )
2617
3921
  else:
2618
- edge_options.add_argument(
2619
- "--window-size=%s,%s" % (
2620
- settings.CHROME_START_WIDTH,
2621
- settings.CHROME_START_HEIGHT,
3922
+ if (
3923
+ hasattr(settings, "CHROME_START_WIDTH")
3924
+ and isinstance(settings.CHROME_START_WIDTH, int)
3925
+ and hasattr(settings, "CHROME_START_HEIGHT")
3926
+ and isinstance(settings.CHROME_START_HEIGHT, int)
3927
+ ):
3928
+ edge_options.add_argument(
3929
+ "--window-size=%s,%s" % (
3930
+ settings.CHROME_START_WIDTH,
3931
+ settings.CHROME_START_HEIGHT,
3932
+ )
2622
3933
  )
2623
- )
2624
3934
  if user_data_dir and not is_using_uc(undetectable, browser_name):
2625
3935
  abs_path = os.path.abspath(user_data_dir)
2626
3936
  edge_options.add_argument("--user-data-dir=%s" % abs_path)
@@ -2641,6 +3951,8 @@ def get_local_driver(
2641
3951
  edge_options.add_argument(
2642
3952
  "--disable-autofill-keyboard-accessory-view[8]"
2643
3953
  )
3954
+ edge_options.add_argument("--safebrowsing-disable-download-protection")
3955
+ edge_options.add_argument("--disable-search-engine-choice-screen")
2644
3956
  edge_options.add_argument("--disable-browser-side-navigation")
2645
3957
  edge_options.add_argument("--disable-translate")
2646
3958
  if not enable_ws:
@@ -2724,7 +4036,10 @@ def get_local_driver(
2724
4036
  edge_options.add_argument("--allow-running-insecure-content")
2725
4037
  if user_agent:
2726
4038
  edge_options.add_argument("--user-agent=%s" % user_agent)
2727
- if IS_LINUX or not is_using_uc(undetectable, browser_name):
4039
+ if (
4040
+ IS_LINUX
4041
+ or (IS_MAC and not is_using_uc(undetectable, browser_name))
4042
+ ):
2728
4043
  edge_options.add_argument("--no-sandbox")
2729
4044
  if remote_debug:
2730
4045
  # To access the Debugger, go to: edge://inspect/#devices
@@ -2749,7 +4064,11 @@ def get_local_driver(
2749
4064
  set_binary = False
2750
4065
  if chromium_arg:
2751
4066
  # Can be a comma-separated list of Chromium args
2752
- chromium_arg_list = chromium_arg.split(",")
4067
+ chromium_arg_list = None
4068
+ if isinstance(chromium_arg, (list, tuple)):
4069
+ chromium_arg_list = chromium_arg
4070
+ else:
4071
+ chromium_arg_list = chromium_arg.split(",")
2753
4072
  for chromium_arg_item in chromium_arg_list:
2754
4073
  chromium_arg_item = chromium_arg_item.strip()
2755
4074
  if not chromium_arg_item.startswith("--"):
@@ -2766,26 +4085,29 @@ def get_local_driver(
2766
4085
  edge_options.add_argument(chromium_arg_item)
2767
4086
  if disable_features:
2768
4087
  extra_disabled_features.extend(disable_features.split(","))
4088
+ edge_options.add_argument(
4089
+ '--simulate-outdated-no-au="Tue, 31 Dec 2099 23:59:59 GMT"'
4090
+ )
4091
+ edge_options.add_argument("--disable-ipc-flooding-protection")
4092
+ edge_options.add_argument("--disable-password-generation")
4093
+ edge_options.add_argument("--disable-domain-reliability")
4094
+ edge_options.add_argument("--disable-breakpad")
2769
4095
  included_disabled_features = []
2770
- if user_data_dir:
2771
- included_disabled_features.append("OptimizationHintsFetching")
2772
- included_disabled_features.append("Translate")
2773
- included_disabled_features.append("OptimizationTargetPrediction")
2774
- included_disabled_features.append("PrivacySandboxSettings4")
2775
- for item in extra_disabled_features:
2776
- if item not in included_disabled_features:
2777
- included_disabled_features.append(item)
2778
- d_f_string = ",".join(included_disabled_features)
2779
- edge_options.add_argument("--disable-features=%s" % d_f_string)
2780
- else:
2781
- included_disabled_features.append("OptimizationHintsFetching")
2782
- included_disabled_features.append("Translate")
2783
- included_disabled_features.append("OptimizationTargetPrediction")
2784
- for item in extra_disabled_features:
2785
- if item not in included_disabled_features:
2786
- included_disabled_features.append(item)
2787
- d_f_string = ",".join(included_disabled_features)
2788
- edge_options.add_argument("--disable-features=%s" % d_f_string)
4096
+ included_disabled_features.append("OptimizationHints")
4097
+ included_disabled_features.append("OptimizationHintsFetching")
4098
+ included_disabled_features.append("Translate")
4099
+ included_disabled_features.append("OptimizationTargetPrediction")
4100
+ included_disabled_features.append("OptimizationGuideModelDownloading")
4101
+ included_disabled_features.append("InsecureDownloadWarnings")
4102
+ included_disabled_features.append("InterestFeedContentSuggestions")
4103
+ included_disabled_features.append("PrivacySandboxSettings4")
4104
+ included_disabled_features.append("SidePanelPinning")
4105
+ included_disabled_features.append("UserAgentClientHint")
4106
+ for item in extra_disabled_features:
4107
+ if item not in included_disabled_features:
4108
+ included_disabled_features.append(item)
4109
+ d_f_string = ",".join(included_disabled_features)
4110
+ edge_options.add_argument("--disable-features=%s" % d_f_string)
2789
4111
  if (set_binary or IS_LINUX) and not binary_location:
2790
4112
  br_app = "edge"
2791
4113
  binary_loc = detect_b_ver.get_binary_location(br_app)
@@ -2840,19 +4162,19 @@ def get_local_driver(
2840
4162
  constants.MultiBrowser.DRIVER_FIXING_LOCK
2841
4163
  )
2842
4164
  with edgedriver_fixing_lock:
2843
- try:
4165
+ with suppress(Exception):
4166
+ shared_utils.make_writable(
4167
+ constants.MultiBrowser.DRIVER_FIXING_LOCK
4168
+ )
4169
+ with suppress(Exception):
2844
4170
  if not _was_driver_repaired():
2845
4171
  _repair_edgedriver(edge_version)
2846
4172
  _mark_driver_repaired()
2847
- except Exception:
2848
- pass
2849
4173
  else:
2850
- try:
4174
+ with suppress(Exception):
2851
4175
  if not _was_driver_repaired():
2852
4176
  _repair_edgedriver(edge_version)
2853
4177
  _mark_driver_repaired()
2854
- except Exception:
2855
- pass
2856
4178
  driver = Edge(service=service, options=edge_options)
2857
4179
  return extend_driver(driver)
2858
4180
  elif browser_name == constants.Browser.SAFARI:
@@ -2898,6 +4220,7 @@ def get_local_driver(
2898
4220
  multi_proxy,
2899
4221
  user_agent,
2900
4222
  recorder_ext,
4223
+ disable_cookies,
2901
4224
  disable_js,
2902
4225
  disable_csp,
2903
4226
  enable_ws,
@@ -2909,6 +4232,7 @@ def get_local_driver(
2909
4232
  log_cdp_events,
2910
4233
  no_sandbox,
2911
4234
  disable_gpu,
4235
+ headless1,
2912
4236
  headless2,
2913
4237
  incognito,
2914
4238
  guest_mode,
@@ -3004,7 +4328,7 @@ def get_local_driver(
3004
4328
  ch_driver_version = None
3005
4329
  path_chromedriver = chromedriver_on_path()
3006
4330
  if os.path.exists(LOCAL_CHROMEDRIVER):
3007
- try:
4331
+ with suppress(Exception):
3008
4332
  output = subprocess.check_output(
3009
4333
  '"%s" --version' % LOCAL_CHROMEDRIVER, shell=True
3010
4334
  )
@@ -3018,8 +4342,6 @@ def get_local_driver(
3018
4342
  ch_driver_version = output
3019
4343
  if driver_version == "keep":
3020
4344
  driver_version = ch_driver_version
3021
- except Exception:
3022
- pass
3023
4345
  elif path_chromedriver:
3024
4346
  try:
3025
4347
  make_driver_executable_if_not(path_chromedriver)
@@ -3028,7 +4350,7 @@ def get_local_driver(
3028
4350
  "\nWarning: Could not make chromedriver"
3029
4351
  " executable: %s" % e
3030
4352
  )
3031
- try:
4353
+ with suppress(Exception):
3032
4354
  output = subprocess.check_output(
3033
4355
  '"%s" --version' % path_chromedriver, shell=True
3034
4356
  )
@@ -3042,8 +4364,6 @@ def get_local_driver(
3042
4364
  ch_driver_version = output
3043
4365
  if driver_version == "keep":
3044
4366
  use_version = ch_driver_version
3045
- except Exception:
3046
- pass
3047
4367
  disable_build_check = True
3048
4368
  uc_driver_version = None
3049
4369
  if is_using_uc(undetectable, browser_name):
@@ -3085,8 +4405,14 @@ def get_local_driver(
3085
4405
  except Exception:
3086
4406
  pass # Will need Xvfb on Linux
3087
4407
  elif headless:
3088
- if "--headless" not in chrome_options.arguments:
3089
- chrome_options.add_argument("--headless")
4408
+ if (
4409
+ "--headless" not in chrome_options.arguments
4410
+ and "--headless=old" not in chrome_options.arguments
4411
+ ):
4412
+ if headless1:
4413
+ chrome_options.add_argument("--headless=old")
4414
+ else:
4415
+ chrome_options.add_argument("--headless")
3090
4416
  if LOCAL_CHROMEDRIVER and os.path.exists(LOCAL_CHROMEDRIVER):
3091
4417
  try:
3092
4418
  make_driver_executable_if_not(LOCAL_CHROMEDRIVER)
@@ -3222,6 +4548,10 @@ def get_local_driver(
3222
4548
  constants.MultiBrowser.DRIVER_FIXING_LOCK
3223
4549
  )
3224
4550
  with chromedriver_fixing_lock:
4551
+ with suppress(Exception):
4552
+ shared_utils.make_writable(
4553
+ constants.MultiBrowser.DRIVER_FIXING_LOCK
4554
+ )
3225
4555
  msg = "chromedriver update needed. Getting it now:"
3226
4556
  if not path_chromedriver:
3227
4557
  msg = "chromedriver not found. Getting it now:"
@@ -3236,7 +4566,7 @@ def get_local_driver(
3236
4566
  if IS_ARM_MAC and use_uc:
3237
4567
  intel_for_uc = True # Use Intel driver for UC Mode
3238
4568
  if os.path.exists(LOCAL_CHROMEDRIVER):
3239
- try:
4569
+ with suppress(Exception):
3240
4570
  output = subprocess.check_output(
3241
4571
  '"%s" --version' % LOCAL_CHROMEDRIVER,
3242
4572
  shell=True,
@@ -3249,8 +4579,6 @@ def get_local_driver(
3249
4579
  output = full_ch_driver_version.split(".")[0]
3250
4580
  if int(output) >= 2:
3251
4581
  ch_driver_version = output
3252
- except Exception:
3253
- pass
3254
4582
  if (
3255
4583
  (
3256
4584
  not use_uc
@@ -3315,15 +4643,23 @@ def get_local_driver(
3315
4643
  constants.MultiBrowser.DRIVER_FIXING_LOCK
3316
4644
  )
3317
4645
  with uc_lock: # Avoid multithreaded issues
4646
+ with suppress(Exception):
4647
+ shared_utils.make_writable(
4648
+ constants.MultiBrowser.DRIVER_FIXING_LOCK
4649
+ )
3318
4650
  if make_uc_driver_from_chromedriver:
3319
4651
  if os.path.exists(LOCAL_CHROMEDRIVER):
3320
- shutil.copyfile(
3321
- LOCAL_CHROMEDRIVER, LOCAL_UC_DRIVER
3322
- )
4652
+ with suppress(Exception):
4653
+ make_driver_executable_if_not(
4654
+ LOCAL_CHROMEDRIVER
4655
+ )
4656
+ shutil.copy2(LOCAL_CHROMEDRIVER, LOCAL_UC_DRIVER)
3323
4657
  elif os.path.exists(path_chromedriver):
3324
- shutil.copyfile(
3325
- path_chromedriver, LOCAL_UC_DRIVER
3326
- )
4658
+ with suppress(Exception):
4659
+ make_driver_executable_if_not(
4660
+ path_chromedriver
4661
+ )
4662
+ shutil.copy2(path_chromedriver, LOCAL_UC_DRIVER)
3327
4663
  try:
3328
4664
  make_driver_executable_if_not(LOCAL_UC_DRIVER)
3329
4665
  except Exception as e:
@@ -3354,6 +4690,12 @@ def get_local_driver(
3354
4690
  chrome_options.arguments.remove(
3355
4691
  "--headless"
3356
4692
  )
4693
+ if "--headless=old" in (
4694
+ chrome_options.arguments
4695
+ ):
4696
+ chrome_options.arguments.remove(
4697
+ "--headless=old"
4698
+ )
3357
4699
  uc_chrome_version = None
3358
4700
  if (
3359
4701
  use_version.isnumeric()
@@ -3388,7 +4730,7 @@ def get_local_driver(
3388
4730
  chrome_options.add_argument(
3389
4731
  "--user-agent=%s" % user_agent
3390
4732
  )
3391
- try:
4733
+ with suppress(Exception):
3392
4734
  if (
3393
4735
  (
3394
4736
  not user_agent
@@ -3397,6 +4739,7 @@ def get_local_driver(
3397
4739
  and uc_chrome_version
3398
4740
  and uc_chrome_version >= 117
3399
4741
  and (headless or headless2)
4742
+ and chromium_arg != "decoy"
3400
4743
  ):
3401
4744
  from seleniumbase.console_scripts import (
3402
4745
  sb_install
@@ -3416,6 +4759,7 @@ def get_local_driver(
3416
4759
  None, # multi_proxy
3417
4760
  None, # user_agent
3418
4761
  None, # recorder_ext
4762
+ disable_cookies,
3419
4763
  disable_js,
3420
4764
  disable_csp,
3421
4765
  enable_ws,
@@ -3427,6 +4771,7 @@ def get_local_driver(
3427
4771
  False, # log_cdp_events
3428
4772
  no_sandbox,
3429
4773
  disable_gpu,
4774
+ False, # headless1
3430
4775
  False, # headless2
3431
4776
  incognito,
3432
4777
  guest_mode,
@@ -3494,7 +4839,7 @@ def get_local_driver(
3494
4839
  service=service,
3495
4840
  options=headless_options,
3496
4841
  )
3497
- try:
4842
+ with suppress(Exception):
3498
4843
  user_agent = driver.execute_script(
3499
4844
  "return navigator.userAgent;"
3500
4845
  )
@@ -3516,16 +4861,12 @@ def get_local_driver(
3516
4861
  "--user-agent=%s" % user_agent
3517
4862
  )
3518
4863
  sb_config.uc_agent_cache = user_agent
3519
- except Exception:
3520
- pass
3521
4864
  driver.quit()
3522
- except Exception:
3523
- pass
4865
+ uc_path = None
4866
+ if os.path.exists(LOCAL_UC_DRIVER):
4867
+ uc_path = LOCAL_UC_DRIVER
4868
+ uc_path = os.path.realpath(uc_path)
3524
4869
  try:
3525
- uc_path = None
3526
- if os.path.exists(LOCAL_UC_DRIVER):
3527
- uc_path = LOCAL_UC_DRIVER
3528
- uc_path = os.path.realpath(uc_path)
3529
4870
  driver = undetected.Chrome(
3530
4871
  options=chrome_options,
3531
4872
  user_data_dir=user_data_dir,
@@ -3538,10 +4879,28 @@ def get_local_driver(
3538
4879
  )
3539
4880
  uc_activated = True
3540
4881
  except URLError as e:
3541
- if cert in e.args[0] and IS_MAC:
4882
+ if (
4883
+ IS_MAC
4884
+ and hasattr(e, "args")
4885
+ and isinstance(e.args, (list, tuple))
4886
+ and cert in e.args[0]
4887
+ ):
3542
4888
  mac_certificate_error = True
3543
4889
  else:
3544
4890
  raise
4891
+ except SessionNotCreatedException:
4892
+ time.sleep(0.2)
4893
+ driver = undetected.Chrome(
4894
+ options=chrome_options,
4895
+ user_data_dir=user_data_dir,
4896
+ driver_executable_path=uc_path,
4897
+ browser_executable_path=b_path,
4898
+ enable_cdp_events=cdp_events,
4899
+ headless=False, # Xvfb needed!
4900
+ version_main=uc_chrome_version,
4901
+ use_subprocess=True, # Always!
4902
+ )
4903
+ uc_activated = True
3545
4904
  if mac_certificate_error:
3546
4905
  cf_lock_path = (
3547
4906
  constants.MultiBrowser.CERT_FIXING_LOCK
@@ -3552,6 +4911,10 @@ def get_local_driver(
3552
4911
  if not os.path.exists(cf_lock_path):
3553
4912
  # Avoid multithreaded issues
3554
4913
  with cf_lock:
4914
+ with suppress(Exception):
4915
+ shared_utils.make_writable(
4916
+ cf_lock_path
4917
+ )
3555
4918
  # Install Python Certificates (MAC)
3556
4919
  os.system(
3557
4920
  r"bash /Applications/Python*/"
@@ -3648,6 +5011,7 @@ def get_local_driver(
3648
5011
  None, # multi_proxy
3649
5012
  None, # user_agent
3650
5013
  None, # recorder_ext
5014
+ disable_cookies,
3651
5015
  disable_js,
3652
5016
  disable_csp,
3653
5017
  enable_ws,
@@ -3659,6 +5023,7 @@ def get_local_driver(
3659
5023
  False, # log_cdp_events
3660
5024
  no_sandbox,
3661
5025
  disable_gpu,
5026
+ False, # headless1
3662
5027
  False, # headless2
3663
5028
  incognito,
3664
5029
  guest_mode,
@@ -3693,6 +5058,10 @@ def get_local_driver(
3693
5058
  constants.MultiBrowser.DRIVER_FIXING_LOCK
3694
5059
  )
3695
5060
  with chromedriver_fixing_lock:
5061
+ with suppress(Exception):
5062
+ shared_utils.make_writable(
5063
+ constants.MultiBrowser.DRIVER_FIXING_LOCK
5064
+ )
3696
5065
  if not _was_driver_repaired():
3697
5066
  _repair_chromedriver(
3698
5067
  chrome_options, headless_options, mcv
@@ -3724,6 +5093,9 @@ def get_local_driver(
3724
5093
  options=chrome_options,
3725
5094
  )
3726
5095
  driver.default_get = driver.get # Save copy of original
5096
+ driver.cdp = None # Set a placeholder
5097
+ driver._is_using_cdp = False
5098
+ driver._is_connected = True
3727
5099
  if uc_activated:
3728
5100
  driver.get = lambda url: uc_special_open_if_cf(
3729
5101
  driver,
@@ -3743,20 +5115,87 @@ def get_local_driver(
3743
5115
  driver, *args, **kwargs
3744
5116
  )
3745
5117
  )
5118
+ driver.uc_open_with_disconnect = (
5119
+ lambda *args, **kwargs: uc_open_with_disconnect(
5120
+ driver, *args, **kwargs
5121
+ )
5122
+ )
3746
5123
  driver.uc_click = lambda *args, **kwargs: uc_click(
3747
5124
  driver, *args, **kwargs
3748
5125
  )
5126
+ driver.uc_activate_cdp_mode = (
5127
+ lambda *args, **kwargs: uc_activate_cdp_mode(
5128
+ driver, *args, **kwargs
5129
+ )
5130
+ )
5131
+ driver.uc_open_with_cdp_mode = (
5132
+ lambda *args, **kwargs: uc_open_with_cdp_mode(
5133
+ driver, *args, **kwargs
5134
+ )
5135
+ )
5136
+ driver.uc_gui_press_key = (
5137
+ lambda *args, **kwargs: uc_gui_press_key(
5138
+ driver, *args, **kwargs
5139
+ )
5140
+ )
5141
+ driver.uc_gui_press_keys = (
5142
+ lambda *args, **kwargs: uc_gui_press_keys(
5143
+ driver, *args, **kwargs
5144
+ )
5145
+ )
5146
+ driver.uc_gui_write = (
5147
+ lambda *args, **kwargs: uc_gui_write(
5148
+ driver, *args, **kwargs
5149
+ )
5150
+ )
5151
+ driver.uc_gui_click_x_y = (
5152
+ lambda *args, **kwargs: uc_gui_click_x_y(
5153
+ driver, *args, **kwargs
5154
+ )
5155
+ )
5156
+ driver.uc_gui_click_captcha = (
5157
+ lambda *args, **kwargs: uc_gui_click_captcha(
5158
+ driver, *args, **kwargs
5159
+ )
5160
+ )
5161
+ driver.uc_gui_click_cf = (
5162
+ lambda *args, **kwargs: uc_gui_click_cf(
5163
+ driver, *args, **kwargs
5164
+ )
5165
+ )
5166
+ driver.uc_gui_click_rc = (
5167
+ lambda *args, **kwargs: uc_gui_click_rc(
5168
+ driver, *args, **kwargs
5169
+ )
5170
+ )
5171
+ driver.uc_gui_handle_captcha = (
5172
+ lambda *args, **kwargs: uc_gui_handle_captcha(
5173
+ driver, *args, **kwargs
5174
+ )
5175
+ )
5176
+ driver.uc_gui_handle_cf = (
5177
+ lambda *args, **kwargs: uc_gui_handle_cf(
5178
+ driver, *args, **kwargs
5179
+ )
5180
+ )
5181
+ driver.uc_gui_handle_rc = (
5182
+ lambda *args, **kwargs: uc_gui_handle_rc(
5183
+ driver, *args, **kwargs
5184
+ )
5185
+ )
3749
5186
  driver.uc_switch_to_frame = (
3750
5187
  lambda *args, **kwargs: uc_switch_to_frame(
3751
5188
  driver, *args, **kwargs
3752
5189
  )
3753
5190
  )
5191
+ driver._is_hidden = (headless or headless2)
5192
+ driver._is_using_uc = True
3754
5193
  if mobile_emulator:
3755
5194
  uc_metrics = {}
3756
5195
  if (
3757
5196
  isinstance(device_width, int)
3758
5197
  and isinstance(device_height, int)
3759
- and isinstance(device_pixel_ratio, int)
5198
+ and isinstance(device_pixel_ratio, (int, float))
3760
5199
  ):
3761
5200
  uc_metrics["width"] = device_width
3762
5201
  uc_metrics["height"] = device_height
@@ -3773,13 +5212,11 @@ def get_local_driver(
3773
5212
  "mobile": True
3774
5213
  }
3775
5214
  )
3776
- try:
5215
+ with suppress(Exception):
3777
5216
  driver.execute_cdp_cmd(
3778
5217
  'Emulation.setDeviceMetricsOverride',
3779
5218
  set_device_metrics_override
3780
5219
  )
3781
- except Exception:
3782
- pass
3783
5220
  return extend_driver(driver)
3784
5221
  else: # Running headless on Linux (and not using --uc)
3785
5222
  try:
@@ -3823,25 +5260,24 @@ def get_local_driver(
3823
5260
  chromedr_fixing_lock = fasteners.InterProcessLock(
3824
5261
  constants.MultiBrowser.DRIVER_FIXING_LOCK
3825
5262
  )
5263
+ D_F_L = constants.MultiBrowser.DRIVER_FIXING_LOCK
3826
5264
  with chromedr_fixing_lock:
5265
+ with suppress(Exception):
5266
+ shared_utils.make_writable(D_F_L)
3827
5267
  if not _was_driver_repaired():
3828
- try:
5268
+ with suppress(Exception):
3829
5269
  _repair_chromedriver(
3830
5270
  chrome_options, chrome_options, mcv
3831
5271
  )
3832
5272
  _mark_driver_repaired()
3833
- except Exception:
3834
- pass
3835
5273
  else:
3836
5274
  if not _was_driver_repaired():
3837
- try:
5275
+ with suppress(Exception):
3838
5276
  _repair_chromedriver(
3839
5277
  chrome_options, chrome_options, mcv
3840
5278
  )
3841
- except Exception:
3842
- pass
3843
5279
  _mark_driver_repaired()
3844
- try:
5280
+ with suppress(Exception):
3845
5281
  service = ChromeService(
3846
5282
  log_output=os.devnull,
3847
5283
  service_args=["--disable-build-check"],
@@ -3851,8 +5287,6 @@ def get_local_driver(
3851
5287
  options=chrome_options,
3852
5288
  )
3853
5289
  return extend_driver(driver)
3854
- except Exception:
3855
- pass
3856
5290
  # Use the virtual display on Linux during headless errors
3857
5291
  logging.debug(
3858
5292
  "\nWarning: Chrome failed to launch in"
@@ -3861,6 +5295,8 @@ def get_local_driver(
3861
5295
  )
3862
5296
  if "--headless" in chrome_options.arguments:
3863
5297
  chrome_options.arguments.remove("--headless")
5298
+ if "--headless=old" in chrome_options.arguments:
5299
+ chrome_options.arguments.remove("--headless=old")
3864
5300
  service = ChromeService(
3865
5301
  log_output=os.devnull,
3866
5302
  service_args=["--disable-build-check"]
@@ -3869,18 +5305,16 @@ def get_local_driver(
3869
5305
  service=service, options=chrome_options
3870
5306
  )
3871
5307
  return extend_driver(driver)
3872
- except Exception:
5308
+ except Exception as original_exception:
3873
5309
  if is_using_uc(undetectable, browser_name):
3874
5310
  raise
3875
5311
  # Try again if Chrome didn't launch
3876
- try:
5312
+ with suppress(Exception):
3877
5313
  service = ChromeService(service_args=["--disable-build-check"])
3878
5314
  driver = webdriver.Chrome(
3879
5315
  service=service, options=chrome_options
3880
5316
  )
3881
5317
  return extend_driver(driver)
3882
- except Exception:
3883
- pass
3884
5318
  if user_data_dir:
3885
5319
  print("\nUnable to set user_data_dir while starting Chrome!\n")
3886
5320
  raise
@@ -3905,8 +5339,11 @@ def get_local_driver(
3905
5339
  log_output=os.devnull,
3906
5340
  service_args=["--disable-build-check"]
3907
5341
  )
3908
- driver = webdriver.Chrome(service=service)
3909
- return extend_driver(driver)
5342
+ try:
5343
+ driver = webdriver.Chrome(service=service)
5344
+ return extend_driver(driver)
5345
+ except Exception:
5346
+ raise original_exception
3910
5347
  else:
3911
5348
  raise Exception(
3912
5349
  "%s is not a valid browser option for this system!" % browser_name