seleniumbase 4.41.3__py3-none-any.whl → 4.45.10__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- sbase/steps.py +9 -0
- seleniumbase/__version__.py +1 -1
- seleniumbase/behave/behave_helper.py +2 -0
- seleniumbase/behave/behave_sb.py +21 -8
- seleniumbase/common/decorators.py +3 -1
- seleniumbase/console_scripts/run.py +1 -0
- seleniumbase/console_scripts/sb_caseplans.py +3 -4
- seleniumbase/console_scripts/sb_install.py +142 -11
- seleniumbase/console_scripts/sb_mkchart.py +1 -2
- seleniumbase/console_scripts/sb_mkdir.py +99 -29
- seleniumbase/console_scripts/sb_mkfile.py +1 -2
- seleniumbase/console_scripts/sb_mkpres.py +1 -2
- seleniumbase/console_scripts/sb_mkrec.py +26 -2
- seleniumbase/console_scripts/sb_objectify.py +4 -5
- seleniumbase/console_scripts/sb_print.py +1 -1
- seleniumbase/console_scripts/sb_recorder.py +40 -3
- seleniumbase/core/browser_launcher.py +474 -151
- seleniumbase/core/detect_b_ver.py +258 -16
- seleniumbase/core/log_helper.py +15 -21
- seleniumbase/core/mysql.py +1 -1
- seleniumbase/core/recorder_helper.py +3 -0
- seleniumbase/core/report_helper.py +9 -12
- seleniumbase/core/sb_cdp.py +734 -215
- seleniumbase/core/sb_driver.py +46 -5
- seleniumbase/core/session_helper.py +2 -4
- seleniumbase/core/tour_helper.py +1 -2
- seleniumbase/drivers/atlas_drivers/__init__.py +0 -0
- seleniumbase/drivers/brave_drivers/__init__.py +0 -0
- seleniumbase/drivers/chromium_drivers/__init__.py +0 -0
- seleniumbase/drivers/comet_drivers/__init__.py +0 -0
- seleniumbase/drivers/opera_drivers/__init__.py +0 -0
- seleniumbase/fixtures/base_case.py +448 -251
- seleniumbase/fixtures/constants.py +36 -9
- seleniumbase/fixtures/js_utils.py +77 -18
- seleniumbase/fixtures/page_actions.py +41 -13
- seleniumbase/fixtures/page_utils.py +19 -12
- seleniumbase/fixtures/shared_utils.py +64 -6
- seleniumbase/masterqa/master_qa.py +16 -2
- seleniumbase/plugins/base_plugin.py +8 -0
- seleniumbase/plugins/basic_test_info.py +2 -3
- seleniumbase/plugins/driver_manager.py +131 -5
- seleniumbase/plugins/page_source.py +2 -3
- seleniumbase/plugins/pytest_plugin.py +244 -79
- seleniumbase/plugins/sb_manager.py +143 -20
- seleniumbase/plugins/selenium_plugin.py +144 -12
- seleniumbase/translate/translator.py +2 -3
- seleniumbase/undetected/__init__.py +17 -13
- seleniumbase/undetected/cdp.py +1 -12
- seleniumbase/undetected/cdp_driver/browser.py +330 -129
- seleniumbase/undetected/cdp_driver/cdp_util.py +328 -61
- seleniumbase/undetected/cdp_driver/config.py +110 -14
- seleniumbase/undetected/cdp_driver/connection.py +18 -48
- seleniumbase/undetected/cdp_driver/element.py +105 -33
- seleniumbase/undetected/cdp_driver/tab.py +414 -39
- seleniumbase/utilities/selenium_grid/download_selenium_server.py +1 -1
- seleniumbase/utilities/selenium_grid/grid_hub.py +1 -2
- seleniumbase/utilities/selenium_grid/grid_node.py +2 -3
- seleniumbase/utilities/selenium_ide/convert_ide.py +2 -3
- {seleniumbase-4.41.3.dist-info → seleniumbase-4.45.10.dist-info}/METADATA +193 -166
- {seleniumbase-4.41.3.dist-info → seleniumbase-4.45.10.dist-info}/RECORD +64 -59
- {seleniumbase-4.41.3.dist-info → seleniumbase-4.45.10.dist-info}/licenses/LICENSE +1 -1
- {seleniumbase-4.41.3.dist-info → seleniumbase-4.45.10.dist-info}/WHEEL +0 -0
- {seleniumbase-4.41.3.dist-info → seleniumbase-4.45.10.dist-info}/entry_points.txt +0 -0
- {seleniumbase-4.41.3.dist-info → seleniumbase-4.45.10.dist-info}/top_level.txt +0 -0
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
from __future__ import annotations
|
|
3
3
|
import asyncio
|
|
4
4
|
import atexit
|
|
5
|
+
import fasteners
|
|
5
6
|
import http.cookiejar
|
|
6
7
|
import json
|
|
7
8
|
import logging
|
|
@@ -15,7 +16,10 @@ import urllib.parse
|
|
|
15
16
|
import urllib.request
|
|
16
17
|
import warnings
|
|
17
18
|
from collections import defaultdict
|
|
19
|
+
from contextlib import suppress
|
|
18
20
|
from seleniumbase import config as sb_config
|
|
21
|
+
from seleniumbase.fixtures import constants
|
|
22
|
+
from seleniumbase.fixtures import shared_utils
|
|
19
23
|
from typing import List, Optional, Set, Tuple, Union
|
|
20
24
|
import mycdp as cdp
|
|
21
25
|
from . import cdp_util as util
|
|
@@ -34,7 +38,7 @@ def get_registered_instances():
|
|
|
34
38
|
def deconstruct_browser():
|
|
35
39
|
for _ in __registered__instances__:
|
|
36
40
|
if not _.stopped:
|
|
37
|
-
_.stop()
|
|
41
|
+
_.stop(deconstruct=True)
|
|
38
42
|
for attempt in range(5):
|
|
39
43
|
try:
|
|
40
44
|
if _.config and not _.config.uses_custom_data_dir:
|
|
@@ -251,6 +255,53 @@ class Browser:
|
|
|
251
255
|
)
|
|
252
256
|
self.targets.remove(current_tab)
|
|
253
257
|
|
|
258
|
+
def get_rd_host(self):
|
|
259
|
+
return self.config.host
|
|
260
|
+
|
|
261
|
+
def get_rd_port(self):
|
|
262
|
+
return self.config.port
|
|
263
|
+
|
|
264
|
+
def get_rd_url(self):
|
|
265
|
+
host = self.config.host
|
|
266
|
+
port = self.config.port
|
|
267
|
+
return f"http://{host}:{port}"
|
|
268
|
+
|
|
269
|
+
def get_endpoint_url(self):
|
|
270
|
+
return self.get_rd_url()
|
|
271
|
+
|
|
272
|
+
def get_port(self):
|
|
273
|
+
return self.get_rd_port()
|
|
274
|
+
|
|
275
|
+
async def set_auth(self, username, password, tab):
|
|
276
|
+
async def auth_challenge_handler(event: cdp.fetch.AuthRequired):
|
|
277
|
+
await tab.send(
|
|
278
|
+
cdp.fetch.continue_with_auth(
|
|
279
|
+
request_id=event.request_id,
|
|
280
|
+
auth_challenge_response=cdp.fetch.AuthChallengeResponse(
|
|
281
|
+
response="ProvideCredentials",
|
|
282
|
+
username=username,
|
|
283
|
+
password=password,
|
|
284
|
+
),
|
|
285
|
+
)
|
|
286
|
+
)
|
|
287
|
+
|
|
288
|
+
async def req_paused(event: cdp.fetch.RequestPaused):
|
|
289
|
+
await tab.send(
|
|
290
|
+
cdp.fetch.continue_request(request_id=event.request_id)
|
|
291
|
+
)
|
|
292
|
+
|
|
293
|
+
tab.add_handler(
|
|
294
|
+
cdp.fetch.RequestPaused,
|
|
295
|
+
lambda event: asyncio.create_task(req_paused(event)),
|
|
296
|
+
)
|
|
297
|
+
|
|
298
|
+
tab.add_handler(
|
|
299
|
+
cdp.fetch.AuthRequired,
|
|
300
|
+
lambda event: asyncio.create_task(auth_challenge_handler(event)),
|
|
301
|
+
)
|
|
302
|
+
|
|
303
|
+
await tab.send(cdp.fetch.enable(handle_auth_requests=True))
|
|
304
|
+
|
|
254
305
|
async def get(
|
|
255
306
|
self,
|
|
256
307
|
url="about:blank",
|
|
@@ -266,6 +317,7 @@ class Browser:
|
|
|
266
317
|
:param new_window: Open new window
|
|
267
318
|
:return: Page
|
|
268
319
|
"""
|
|
320
|
+
await asyncio.sleep(0.005)
|
|
269
321
|
if url and ":" not in url:
|
|
270
322
|
url = "https://" + url
|
|
271
323
|
if new_tab or new_window:
|
|
@@ -277,115 +329,210 @@ class Browser:
|
|
|
277
329
|
)
|
|
278
330
|
connection: tab.Tab = next(
|
|
279
331
|
filter(
|
|
280
|
-
lambda item:
|
|
332
|
+
lambda item: (
|
|
333
|
+
item.type_ == "page" and item.target_id == target_id
|
|
334
|
+
),
|
|
281
335
|
self.targets,
|
|
282
336
|
)
|
|
283
337
|
)
|
|
284
338
|
connection.browser = self
|
|
285
339
|
else:
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
340
|
+
try:
|
|
341
|
+
# Most recently opened tab
|
|
342
|
+
connection = self.targets[-1]
|
|
343
|
+
await connection.sleep(0.005)
|
|
344
|
+
except Exception:
|
|
345
|
+
# First tab from browser.tabs
|
|
346
|
+
connection: tab.Tab = next(
|
|
347
|
+
filter(lambda item: item.type_ == "page", self.targets)
|
|
348
|
+
)
|
|
349
|
+
await connection.sleep(0.005)
|
|
350
|
+
_cdp_timezone = None
|
|
351
|
+
_cdp_user_agent = ""
|
|
352
|
+
_cdp_locale = None
|
|
353
|
+
_cdp_platform = None
|
|
354
|
+
_cdp_disable_csp = None
|
|
355
|
+
_cdp_geolocation = None
|
|
356
|
+
_cdp_mobile_mode = None
|
|
357
|
+
_cdp_recorder = None
|
|
358
|
+
_cdp_ad_block = None
|
|
359
|
+
if getattr(sb_config, "_cdp_timezone", None):
|
|
360
|
+
_cdp_timezone = sb_config._cdp_timezone
|
|
361
|
+
if getattr(sb_config, "_cdp_user_agent", None):
|
|
362
|
+
_cdp_user_agent = sb_config._cdp_user_agent
|
|
363
|
+
if getattr(sb_config, "_cdp_locale", None):
|
|
364
|
+
_cdp_locale = sb_config._cdp_locale
|
|
365
|
+
if getattr(sb_config, "_cdp_platform", None):
|
|
366
|
+
_cdp_platform = sb_config._cdp_platform
|
|
367
|
+
if getattr(sb_config, "_cdp_geolocation", None):
|
|
368
|
+
_cdp_geolocation = sb_config._cdp_geolocation
|
|
369
|
+
if getattr(sb_config, "_cdp_mobile_mode", None):
|
|
370
|
+
_cdp_mobile_mode = sb_config._cdp_mobile_mode
|
|
371
|
+
if getattr(sb_config, "ad_block_on", None):
|
|
372
|
+
_cdp_ad_block = sb_config.ad_block_on
|
|
373
|
+
if getattr(sb_config, "disable_csp", None):
|
|
374
|
+
_cdp_disable_csp = sb_config.disable_csp
|
|
375
|
+
if "timezone" in kwargs:
|
|
376
|
+
_cdp_timezone = kwargs["timezone"]
|
|
377
|
+
elif "tzone" in kwargs:
|
|
378
|
+
_cdp_timezone = kwargs["tzone"]
|
|
379
|
+
if "user_agent" in kwargs:
|
|
380
|
+
_cdp_user_agent = kwargs["user_agent"]
|
|
381
|
+
elif "agent" in kwargs:
|
|
382
|
+
_cdp_user_agent = kwargs["agent"]
|
|
383
|
+
if "locale" in kwargs:
|
|
384
|
+
_cdp_locale = kwargs["locale"]
|
|
385
|
+
elif "lang" in kwargs:
|
|
386
|
+
_cdp_locale = kwargs["lang"]
|
|
387
|
+
elif "locale_code" in kwargs:
|
|
388
|
+
_cdp_locale = kwargs["locale_code"]
|
|
389
|
+
if "platform" in kwargs:
|
|
390
|
+
_cdp_platform = kwargs["platform"]
|
|
391
|
+
elif "plat" in kwargs:
|
|
392
|
+
_cdp_platform = kwargs["plat"]
|
|
393
|
+
if "disable_csp" in kwargs:
|
|
394
|
+
_cdp_disable_csp = kwargs["disable_csp"]
|
|
395
|
+
if "geolocation" in kwargs:
|
|
396
|
+
_cdp_geolocation = kwargs["geolocation"]
|
|
397
|
+
elif "geoloc" in kwargs:
|
|
398
|
+
_cdp_geolocation = kwargs["geoloc"]
|
|
399
|
+
if "ad_block" in kwargs:
|
|
400
|
+
_cdp_ad_block = kwargs["ad_block"]
|
|
401
|
+
if "mobile" in kwargs:
|
|
402
|
+
_cdp_mobile_mode = kwargs["mobile"]
|
|
403
|
+
if "recorder" in kwargs:
|
|
404
|
+
_cdp_recorder = kwargs["recorder"]
|
|
405
|
+
await connection.sleep(0.01)
|
|
406
|
+
await connection.send(cdp.network.enable())
|
|
407
|
+
await connection.sleep(0.01)
|
|
408
|
+
if _cdp_timezone:
|
|
409
|
+
await connection.set_timezone(_cdp_timezone)
|
|
410
|
+
if _cdp_locale:
|
|
411
|
+
await connection.set_locale(_cdp_locale)
|
|
412
|
+
if _cdp_user_agent or _cdp_locale or _cdp_platform:
|
|
413
|
+
await connection.set_user_agent(
|
|
414
|
+
user_agent=_cdp_user_agent,
|
|
415
|
+
accept_language=_cdp_locale,
|
|
416
|
+
platform=_cdp_platform,
|
|
289
417
|
)
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
elif "geoloc" in kwargs:
|
|
335
|
-
_cdp_geolocation = kwargs["geoloc"]
|
|
336
|
-
if "recorder" in kwargs:
|
|
337
|
-
_cdp_recorder = kwargs["recorder"]
|
|
338
|
-
if _cdp_timezone:
|
|
339
|
-
await connection.send(cdp.page.navigate("about:blank"))
|
|
340
|
-
await connection.set_timezone(_cdp_timezone)
|
|
341
|
-
if _cdp_locale:
|
|
342
|
-
await connection.set_locale(_cdp_locale)
|
|
343
|
-
if _cdp_user_agent or _cdp_locale or _cdp_platform:
|
|
344
|
-
await connection.send(cdp.page.navigate("about:blank"))
|
|
345
|
-
await connection.set_user_agent(
|
|
346
|
-
user_agent=_cdp_user_agent,
|
|
347
|
-
accept_language=_cdp_locale,
|
|
348
|
-
platform=_cdp_platform,
|
|
418
|
+
if _cdp_ad_block:
|
|
419
|
+
await connection.send(cdp.network.set_blocked_urls(
|
|
420
|
+
urls=[
|
|
421
|
+
"*.cloudflareinsights.com*",
|
|
422
|
+
"*.googlesyndication.com*",
|
|
423
|
+
"*.googletagmanager.com*",
|
|
424
|
+
"*.google-analytics.com*",
|
|
425
|
+
"*.amazon-adsystem.com*",
|
|
426
|
+
"*.adsafeprotected.com*",
|
|
427
|
+
"*.ads.linkedin.com*",
|
|
428
|
+
"*.casalemedia.com*",
|
|
429
|
+
"*.doubleclick.net*",
|
|
430
|
+
"*.admanmedia.com*",
|
|
431
|
+
"*.quantserve.com*",
|
|
432
|
+
"*.fastclick.net*",
|
|
433
|
+
"*.snigelweb.com*",
|
|
434
|
+
"*.bidswitch.net*",
|
|
435
|
+
"*.360yield.com*",
|
|
436
|
+
"*.adthrive.com*",
|
|
437
|
+
"*.pubmatic.com*",
|
|
438
|
+
"*.id5-sync.com*",
|
|
439
|
+
"*.dotomi.com*",
|
|
440
|
+
"*.adsrvr.org*",
|
|
441
|
+
"*.atmtd.com*",
|
|
442
|
+
"*.liadm.com*",
|
|
443
|
+
"*.loopme.me*",
|
|
444
|
+
"*.adnxs.com*",
|
|
445
|
+
"*.openx.net*",
|
|
446
|
+
"*.tapad.com*",
|
|
447
|
+
"*.3lift.com*",
|
|
448
|
+
"*.turn.com*",
|
|
449
|
+
"*.2mdn.net*",
|
|
450
|
+
"*.cpx.to*",
|
|
451
|
+
"*.ad.gt*",
|
|
452
|
+
]
|
|
453
|
+
))
|
|
454
|
+
if _cdp_geolocation:
|
|
455
|
+
await connection.set_geolocation(_cdp_geolocation)
|
|
456
|
+
if _cdp_disable_csp:
|
|
457
|
+
await connection.send(cdp.page.set_bypass_csp(enabled=True))
|
|
458
|
+
if _cdp_mobile_mode:
|
|
459
|
+
await connection.send(
|
|
460
|
+
cdp.emulation.set_device_metrics_override(
|
|
461
|
+
width=412, height=732, device_scale_factor=3, mobile=True
|
|
349
462
|
)
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
463
|
+
)
|
|
464
|
+
# (The code below is for the Chrome 142 extension fix)
|
|
465
|
+
if (
|
|
466
|
+
getattr(sb_config, "_cdp_proxy", None)
|
|
467
|
+
and "@" in sb_config._cdp_proxy
|
|
468
|
+
and "auth" not in kwargs
|
|
469
|
+
):
|
|
470
|
+
username_and_password = sb_config._cdp_proxy.split("@")[0]
|
|
471
|
+
proxy_user = username_and_password.split(":")[0]
|
|
472
|
+
proxy_pass = username_and_password.split(":")[1]
|
|
354
473
|
if (
|
|
355
|
-
hasattr(
|
|
356
|
-
and
|
|
357
|
-
and sb_config._cdp_proxy
|
|
358
|
-
and "auth" not in kwargs
|
|
474
|
+
hasattr(self.main_tab, "_last_auth")
|
|
475
|
+
and self.main_tab._last_auth == username_and_password
|
|
359
476
|
):
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
await
|
|
364
|
-
proxy_user, proxy_pass, self.tabs[0]
|
|
365
|
-
)
|
|
477
|
+
pass # Auth was already set
|
|
478
|
+
else:
|
|
479
|
+
self.main_tab._last_auth = username_and_password
|
|
480
|
+
await self.set_auth(proxy_user, proxy_pass, self.tabs[0])
|
|
366
481
|
time.sleep(0.25)
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
482
|
+
if "auth" in kwargs and kwargs["auth"] and ":" in kwargs["auth"]:
|
|
483
|
+
username_and_password = kwargs["auth"]
|
|
484
|
+
proxy_user = username_and_password.split(":")[0]
|
|
485
|
+
proxy_pass = username_and_password.split(":")[1]
|
|
486
|
+
if (
|
|
487
|
+
hasattr(self.main_tab, "_last_auth")
|
|
488
|
+
and self.main_tab._last_auth == username_and_password
|
|
489
|
+
):
|
|
490
|
+
pass # Auth was already set
|
|
491
|
+
else:
|
|
492
|
+
self.main_tab._last_auth = username_and_password
|
|
493
|
+
await self.set_auth(proxy_user, proxy_pass, self.tabs[0])
|
|
374
494
|
time.sleep(0.25)
|
|
375
|
-
|
|
376
|
-
|
|
495
|
+
await connection.sleep(0.15)
|
|
496
|
+
frame_id, loader_id, *_ = await connection.send(
|
|
497
|
+
cdp.page.navigate(url)
|
|
498
|
+
)
|
|
499
|
+
major_browser_version = None
|
|
500
|
+
try:
|
|
501
|
+
major_browser_version = (
|
|
502
|
+
int(self.info["Browser"].split("/")[-1].split(".")[0])
|
|
377
503
|
)
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
504
|
+
except Exception:
|
|
505
|
+
pass
|
|
506
|
+
if (
|
|
507
|
+
_cdp_recorder
|
|
508
|
+
and (
|
|
509
|
+
not hasattr(sb_config, "browser")
|
|
510
|
+
or (
|
|
511
|
+
sb_config.browser == "chrome"
|
|
512
|
+
and (
|
|
513
|
+
not major_browser_version
|
|
514
|
+
or major_browser_version >= 142
|
|
515
|
+
)
|
|
383
516
|
)
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
517
|
+
)
|
|
518
|
+
):
|
|
519
|
+
# (The code below is for the Chrome 142 extension fix)
|
|
520
|
+
from seleniumbase.js_code.recorder_js import recorder_js
|
|
521
|
+
recorder_code = (
|
|
522
|
+
"""window.onload = function() { %s };""" % recorder_js
|
|
523
|
+
)
|
|
524
|
+
await connection.send(
|
|
525
|
+
cdp.page.add_script_to_evaluate_on_new_document(recorder_code)
|
|
526
|
+
)
|
|
527
|
+
await connection.sleep(0.25)
|
|
528
|
+
await self.wait(0.05)
|
|
529
|
+
await connection.send(cdp.runtime.evaluate(recorder_js))
|
|
530
|
+
# Update the frame_id on the tab
|
|
531
|
+
connection.frame_id = frame_id
|
|
532
|
+
connection.browser = self
|
|
533
|
+
# Give settings time to take effect
|
|
388
534
|
await connection.sleep(0.25)
|
|
535
|
+
await self.wait(0.05)
|
|
389
536
|
return connection
|
|
390
537
|
|
|
391
538
|
async def start(self=None) -> Browser:
|
|
@@ -437,7 +584,7 @@ class Browser:
|
|
|
437
584
|
) # noqa
|
|
438
585
|
exe = self.config.browser_executable_path
|
|
439
586
|
params = self.config()
|
|
440
|
-
logger.
|
|
587
|
+
logger.debug(
|
|
441
588
|
"Starting\n\texecutable :%s\n\narguments:\n%s",
|
|
442
589
|
exe,
|
|
443
590
|
"\n\t".join(params),
|
|
@@ -471,20 +618,29 @@ class Browser:
|
|
|
471
618
|
else:
|
|
472
619
|
break
|
|
473
620
|
if not self.info:
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
621
|
+
chromium = "Chromium"
|
|
622
|
+
if getattr(sb_config, "_cdp_browser", None):
|
|
623
|
+
chromium = sb_config._cdp_browser
|
|
624
|
+
chromium = chromium[0].upper() + chromium[1:]
|
|
625
|
+
message = "Failed to connect to the browser"
|
|
626
|
+
if not exe or not os.path.exists(exe):
|
|
627
|
+
message = (
|
|
628
|
+
"%s executable not found. Is it installed?" % chromium
|
|
481
629
|
)
|
|
630
|
+
dash_len = len(message)
|
|
631
|
+
dashes = "-" * dash_len
|
|
632
|
+
raise Exception(
|
|
633
|
+
"""
|
|
634
|
+
%s
|
|
635
|
+
%s
|
|
636
|
+
%s
|
|
637
|
+
""" % (dashes, message, dashes)
|
|
482
638
|
)
|
|
483
639
|
self.connection = Connection(
|
|
484
|
-
self.info.webSocketDebuggerUrl,
|
|
640
|
+
self.info.webSocketDebuggerUrl, browser=self
|
|
485
641
|
)
|
|
486
642
|
if self.config.autodiscover_targets:
|
|
487
|
-
logger.
|
|
643
|
+
logger.debug("Enabling autodiscover targets")
|
|
488
644
|
self.connection.handlers[cdp.target.TargetInfoChanged] = [
|
|
489
645
|
self._handle_target_update
|
|
490
646
|
]
|
|
@@ -580,8 +736,11 @@ class Browser:
|
|
|
580
736
|
try:
|
|
581
737
|
import mss
|
|
582
738
|
except Exception:
|
|
583
|
-
|
|
584
|
-
|
|
739
|
+
pip_find_lock = fasteners.InterProcessLock(
|
|
740
|
+
constants.PipInstall.FINDLOCK
|
|
741
|
+
)
|
|
742
|
+
with pip_find_lock: # Prevent issues with multiple processes
|
|
743
|
+
shared_utils.pip_install("mss")
|
|
585
744
|
import mss
|
|
586
745
|
m = mss.mss()
|
|
587
746
|
screen, screen_width, screen_height = 3 * (None,)
|
|
@@ -655,7 +814,7 @@ class Browser:
|
|
|
655
814
|
f"/{t.target_id}"
|
|
656
815
|
),
|
|
657
816
|
target=t,
|
|
658
|
-
|
|
817
|
+
browser=self,
|
|
659
818
|
)
|
|
660
819
|
)
|
|
661
820
|
await asyncio.sleep(0)
|
|
@@ -690,11 +849,17 @@ class Browser:
|
|
|
690
849
|
else:
|
|
691
850
|
del self._i
|
|
692
851
|
|
|
693
|
-
def stop(self):
|
|
852
|
+
def stop(self, deconstruct=False):
|
|
853
|
+
if (
|
|
854
|
+
not hasattr(sb_config, "_closed_connection_ids")
|
|
855
|
+
or not isinstance(sb_config._closed_connection_ids, list)
|
|
856
|
+
):
|
|
857
|
+
sb_config._closed_connection_ids = []
|
|
858
|
+
connection_id = None
|
|
859
|
+
with suppress(Exception):
|
|
860
|
+
connection_id = self.connection.websocket.id.hex
|
|
861
|
+
close_success = False
|
|
694
862
|
try:
|
|
695
|
-
# asyncio.get_running_loop().create_task(
|
|
696
|
-
# self.connection.send(cdp.browser.close())
|
|
697
|
-
# )
|
|
698
863
|
if self.connection:
|
|
699
864
|
asyncio.get_event_loop().create_task(self.connection.aclose())
|
|
700
865
|
logger.debug(
|
|
@@ -703,23 +868,26 @@ class Browser:
|
|
|
703
868
|
except RuntimeError:
|
|
704
869
|
if self.connection:
|
|
705
870
|
try:
|
|
706
|
-
# asyncio.run(self.connection.send(cdp.browser.close()))
|
|
707
871
|
asyncio.run(self.connection.aclose())
|
|
708
872
|
logger.debug("Closed the connection using asyncio.run()")
|
|
709
873
|
except Exception:
|
|
710
874
|
pass
|
|
711
875
|
for _ in range(3):
|
|
712
876
|
try:
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
877
|
+
if connection_id not in sb_config._closed_connection_ids:
|
|
878
|
+
self._process.terminate()
|
|
879
|
+
logger.debug(
|
|
880
|
+
"Terminated browser with pid %d successfully."
|
|
881
|
+
% self._process.pid
|
|
882
|
+
)
|
|
883
|
+
if connection_id:
|
|
884
|
+
sb_config._closed_connection_ids.append(connection_id)
|
|
885
|
+
close_success = True
|
|
886
|
+
break
|
|
719
887
|
except (Exception,):
|
|
720
888
|
try:
|
|
721
889
|
self._process.kill()
|
|
722
|
-
logger.
|
|
890
|
+
logger.debug(
|
|
723
891
|
"Killed browser with pid %d successfully."
|
|
724
892
|
% self._process.pid
|
|
725
893
|
)
|
|
@@ -728,14 +896,14 @@ class Browser:
|
|
|
728
896
|
try:
|
|
729
897
|
if hasattr(self, "browser_process_pid"):
|
|
730
898
|
os.kill(self._process_pid, 15)
|
|
731
|
-
logger.
|
|
899
|
+
logger.debug(
|
|
732
900
|
"Killed browser with pid %d "
|
|
733
901
|
"using signal 15 successfully."
|
|
734
902
|
% self._process.pid
|
|
735
903
|
)
|
|
736
904
|
break
|
|
737
905
|
except (TypeError,):
|
|
738
|
-
logger.info("
|
|
906
|
+
logger.info("TypeError", exc_info=True)
|
|
739
907
|
pass
|
|
740
908
|
except (PermissionError,):
|
|
741
909
|
logger.info(
|
|
@@ -744,12 +912,45 @@ class Browser:
|
|
|
744
912
|
)
|
|
745
913
|
pass
|
|
746
914
|
except (ProcessLookupError,):
|
|
747
|
-
logger.info("
|
|
915
|
+
logger.info("ProcessLookupError")
|
|
748
916
|
pass
|
|
749
917
|
except (Exception,):
|
|
750
918
|
raise
|
|
751
919
|
self._process = None
|
|
752
920
|
self._process_pid = None
|
|
921
|
+
if (
|
|
922
|
+
hasattr(sb_config, "_xvfb_users")
|
|
923
|
+
and isinstance(sb_config._xvfb_users, int)
|
|
924
|
+
and close_success
|
|
925
|
+
and hasattr(sb_config, "_virtual_display")
|
|
926
|
+
and sb_config._virtual_display
|
|
927
|
+
):
|
|
928
|
+
sb_config._xvfb_users -= 1
|
|
929
|
+
if sb_config._xvfb_users < 0:
|
|
930
|
+
sb_config._xvfb_users = 0
|
|
931
|
+
if (
|
|
932
|
+
shared_utils.is_linux()
|
|
933
|
+
and (
|
|
934
|
+
hasattr(sb_config, "_virtual_display")
|
|
935
|
+
and sb_config._virtual_display
|
|
936
|
+
and hasattr(sb_config._virtual_display, "stop")
|
|
937
|
+
)
|
|
938
|
+
and sb_config._xvfb_users == 0
|
|
939
|
+
):
|
|
940
|
+
try:
|
|
941
|
+
sb_config._virtual_display.stop()
|
|
942
|
+
sb_config._virtual_display = None
|
|
943
|
+
sb_config.headless_active = False
|
|
944
|
+
except AttributeError:
|
|
945
|
+
pass
|
|
946
|
+
except Exception:
|
|
947
|
+
pass
|
|
948
|
+
if (
|
|
949
|
+
deconstruct
|
|
950
|
+
and connection_id
|
|
951
|
+
and connection_id in sb_config._closed_connection_ids
|
|
952
|
+
):
|
|
953
|
+
sb_config._closed_connection_ids.remove(connection_id)
|
|
753
954
|
|
|
754
955
|
def quit(self):
|
|
755
956
|
self.stop()
|
|
@@ -781,7 +982,7 @@ class CookieJar:
|
|
|
781
982
|
"""
|
|
782
983
|
connection = None
|
|
783
984
|
for _tab in self._browser.tabs:
|
|
784
|
-
if
|
|
985
|
+
if getattr(_tab, "closed", None):
|
|
785
986
|
continue
|
|
786
987
|
connection = _tab
|
|
787
988
|
break
|
|
@@ -811,7 +1012,7 @@ class CookieJar:
|
|
|
811
1012
|
"""
|
|
812
1013
|
connection = None
|
|
813
1014
|
for _tab in self._browser.tabs:
|
|
814
|
-
if
|
|
1015
|
+
if getattr(_tab, "closed", None):
|
|
815
1016
|
continue
|
|
816
1017
|
connection = _tab
|
|
817
1018
|
break
|
|
@@ -838,7 +1039,7 @@ class CookieJar:
|
|
|
838
1039
|
save_path = pathlib.Path(file).resolve()
|
|
839
1040
|
connection = None
|
|
840
1041
|
for _tab in self._browser.tabs:
|
|
841
|
-
if
|
|
1042
|
+
if getattr(_tab, "closed", None):
|
|
842
1043
|
continue
|
|
843
1044
|
connection = _tab
|
|
844
1045
|
break
|
|
@@ -884,7 +1085,7 @@ class CookieJar:
|
|
|
884
1085
|
included_cookies = []
|
|
885
1086
|
connection = None
|
|
886
1087
|
for _tab in self._browser.tabs:
|
|
887
|
-
if
|
|
1088
|
+
if getattr(_tab, "closed", None):
|
|
888
1089
|
continue
|
|
889
1090
|
connection = _tab
|
|
890
1091
|
break
|
|
@@ -907,7 +1108,7 @@ class CookieJar:
|
|
|
907
1108
|
"""
|
|
908
1109
|
connection = None
|
|
909
1110
|
for _tab in self._browser.tabs:
|
|
910
|
-
if
|
|
1111
|
+
if getattr(_tab, "closed", None):
|
|
911
1112
|
continue
|
|
912
1113
|
connection = _tab
|
|
913
1114
|
break
|