seleniumbase 4.44.2__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.
- seleniumbase/__version__.py +1 -1
- seleniumbase/behave/behave_sb.py +14 -0
- seleniumbase/console_scripts/run.py +1 -0
- seleniumbase/console_scripts/sb_install.py +142 -11
- seleniumbase/console_scripts/sb_mkdir.py +76 -0
- seleniumbase/console_scripts/sb_mkrec.py +25 -0
- seleniumbase/console_scripts/sb_recorder.py +40 -3
- seleniumbase/core/browser_launcher.py +279 -117
- seleniumbase/core/detect_b_ver.py +8 -6
- seleniumbase/core/log_helper.py +11 -16
- seleniumbase/core/mysql.py +1 -1
- seleniumbase/core/report_helper.py +3 -7
- seleniumbase/core/sb_cdp.py +275 -78
- seleniumbase/core/sb_driver.py +36 -5
- seleniumbase/core/session_helper.py +2 -4
- seleniumbase/drivers/chromium_drivers/__init__.py +0 -0
- seleniumbase/fixtures/base_case.py +251 -201
- seleniumbase/fixtures/constants.py +1 -0
- seleniumbase/fixtures/js_utils.py +52 -14
- seleniumbase/fixtures/page_actions.py +18 -7
- seleniumbase/fixtures/page_utils.py +4 -2
- seleniumbase/fixtures/shared_utils.py +2 -4
- seleniumbase/masterqa/master_qa.py +16 -2
- seleniumbase/plugins/base_plugin.py +8 -0
- seleniumbase/plugins/driver_manager.py +15 -5
- seleniumbase/plugins/pytest_plugin.py +43 -57
- seleniumbase/plugins/sb_manager.py +23 -19
- seleniumbase/plugins/selenium_plugin.py +20 -13
- seleniumbase/undetected/__init__.py +11 -10
- seleniumbase/undetected/cdp.py +1 -12
- seleniumbase/undetected/cdp_driver/browser.py +330 -128
- seleniumbase/undetected/cdp_driver/cdp_util.py +48 -14
- seleniumbase/undetected/cdp_driver/config.py +78 -11
- seleniumbase/undetected/cdp_driver/connection.py +15 -43
- seleniumbase/undetected/cdp_driver/element.py +37 -22
- seleniumbase/undetected/cdp_driver/tab.py +414 -39
- {seleniumbase-4.44.2.dist-info → seleniumbase-4.45.10.dist-info}/METADATA +140 -152
- {seleniumbase-4.44.2.dist-info → seleniumbase-4.45.10.dist-info}/RECORD +42 -41
- {seleniumbase-4.44.2.dist-info → seleniumbase-4.45.10.dist-info}/licenses/LICENSE +1 -1
- {seleniumbase-4.44.2.dist-info → seleniumbase-4.45.10.dist-info}/WHEEL +0 -0
- {seleniumbase-4.44.2.dist-info → seleniumbase-4.45.10.dist-info}/entry_points.txt +0 -0
- {seleniumbase-4.44.2.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,114 +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
|
-
|
|
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
|
|
462
|
+
)
|
|
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]
|
|
309
473
|
if (
|
|
310
|
-
hasattr(
|
|
311
|
-
and
|
|
474
|
+
hasattr(self.main_tab, "_last_auth")
|
|
475
|
+
and self.main_tab._last_auth == username_and_password
|
|
312
476
|
):
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
if "locale" in kwargs:
|
|
323
|
-
_cdp_locale = kwargs["locale"]
|
|
324
|
-
elif "lang" in kwargs:
|
|
325
|
-
_cdp_locale = kwargs["lang"]
|
|
326
|
-
elif "locale_code" in kwargs:
|
|
327
|
-
_cdp_locale = kwargs["locale_code"]
|
|
328
|
-
if "platform" in kwargs:
|
|
329
|
-
_cdp_platform = kwargs["platform"]
|
|
330
|
-
elif "plat" in kwargs:
|
|
331
|
-
_cdp_platform = kwargs["plat"]
|
|
332
|
-
if "geolocation" in kwargs:
|
|
333
|
-
_cdp_geolocation = kwargs["geolocation"]
|
|
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,
|
|
349
|
-
)
|
|
350
|
-
if _cdp_geolocation:
|
|
351
|
-
await connection.send(cdp.page.navigate("about:blank"))
|
|
352
|
-
await connection.set_geolocation(_cdp_geolocation)
|
|
353
|
-
# This part isn't needed now, but may be needed later
|
|
354
|
-
"""
|
|
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])
|
|
481
|
+
time.sleep(0.25)
|
|
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]
|
|
355
486
|
if (
|
|
356
|
-
hasattr(
|
|
357
|
-
and
|
|
358
|
-
and sb_config._cdp_proxy
|
|
359
|
-
and "auth" not in kwargs
|
|
487
|
+
hasattr(self.main_tab, "_last_auth")
|
|
488
|
+
and self.main_tab._last_auth == username_and_password
|
|
360
489
|
):
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
await
|
|
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])
|
|
365
494
|
time.sleep(0.25)
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
frame_id, loader_id, *_ = await connection.send(
|
|
375
|
-
cdp.page.navigate(url)
|
|
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])
|
|
376
503
|
)
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
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
|
+
)
|
|
382
516
|
)
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
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
|
|
387
534
|
await connection.sleep(0.25)
|
|
535
|
+
await self.wait(0.05)
|
|
388
536
|
return connection
|
|
389
537
|
|
|
390
538
|
async def start(self=None) -> Browser:
|
|
@@ -436,7 +584,7 @@ class Browser:
|
|
|
436
584
|
) # noqa
|
|
437
585
|
exe = self.config.browser_executable_path
|
|
438
586
|
params = self.config()
|
|
439
|
-
logger.
|
|
587
|
+
logger.debug(
|
|
440
588
|
"Starting\n\texecutable :%s\n\narguments:\n%s",
|
|
441
589
|
exe,
|
|
442
590
|
"\n\t".join(params),
|
|
@@ -470,20 +618,29 @@ class Browser:
|
|
|
470
618
|
else:
|
|
471
619
|
break
|
|
472
620
|
if not self.info:
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
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
|
|
480
629
|
)
|
|
630
|
+
dash_len = len(message)
|
|
631
|
+
dashes = "-" * dash_len
|
|
632
|
+
raise Exception(
|
|
633
|
+
"""
|
|
634
|
+
%s
|
|
635
|
+
%s
|
|
636
|
+
%s
|
|
637
|
+
""" % (dashes, message, dashes)
|
|
481
638
|
)
|
|
482
639
|
self.connection = Connection(
|
|
483
|
-
self.info.webSocketDebuggerUrl,
|
|
640
|
+
self.info.webSocketDebuggerUrl, browser=self
|
|
484
641
|
)
|
|
485
642
|
if self.config.autodiscover_targets:
|
|
486
|
-
logger.
|
|
643
|
+
logger.debug("Enabling autodiscover targets")
|
|
487
644
|
self.connection.handlers[cdp.target.TargetInfoChanged] = [
|
|
488
645
|
self._handle_target_update
|
|
489
646
|
]
|
|
@@ -579,8 +736,11 @@ class Browser:
|
|
|
579
736
|
try:
|
|
580
737
|
import mss
|
|
581
738
|
except Exception:
|
|
582
|
-
|
|
583
|
-
|
|
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")
|
|
584
744
|
import mss
|
|
585
745
|
m = mss.mss()
|
|
586
746
|
screen, screen_width, screen_height = 3 * (None,)
|
|
@@ -654,7 +814,7 @@ class Browser:
|
|
|
654
814
|
f"/{t.target_id}"
|
|
655
815
|
),
|
|
656
816
|
target=t,
|
|
657
|
-
|
|
817
|
+
browser=self,
|
|
658
818
|
)
|
|
659
819
|
)
|
|
660
820
|
await asyncio.sleep(0)
|
|
@@ -689,11 +849,17 @@ class Browser:
|
|
|
689
849
|
else:
|
|
690
850
|
del self._i
|
|
691
851
|
|
|
692
|
-
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
|
|
693
862
|
try:
|
|
694
|
-
# asyncio.get_running_loop().create_task(
|
|
695
|
-
# self.connection.send(cdp.browser.close())
|
|
696
|
-
# )
|
|
697
863
|
if self.connection:
|
|
698
864
|
asyncio.get_event_loop().create_task(self.connection.aclose())
|
|
699
865
|
logger.debug(
|
|
@@ -702,23 +868,26 @@ class Browser:
|
|
|
702
868
|
except RuntimeError:
|
|
703
869
|
if self.connection:
|
|
704
870
|
try:
|
|
705
|
-
# asyncio.run(self.connection.send(cdp.browser.close()))
|
|
706
871
|
asyncio.run(self.connection.aclose())
|
|
707
872
|
logger.debug("Closed the connection using asyncio.run()")
|
|
708
873
|
except Exception:
|
|
709
874
|
pass
|
|
710
875
|
for _ in range(3):
|
|
711
876
|
try:
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
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
|
|
718
887
|
except (Exception,):
|
|
719
888
|
try:
|
|
720
889
|
self._process.kill()
|
|
721
|
-
logger.
|
|
890
|
+
logger.debug(
|
|
722
891
|
"Killed browser with pid %d successfully."
|
|
723
892
|
% self._process.pid
|
|
724
893
|
)
|
|
@@ -727,14 +896,14 @@ class Browser:
|
|
|
727
896
|
try:
|
|
728
897
|
if hasattr(self, "browser_process_pid"):
|
|
729
898
|
os.kill(self._process_pid, 15)
|
|
730
|
-
logger.
|
|
899
|
+
logger.debug(
|
|
731
900
|
"Killed browser with pid %d "
|
|
732
901
|
"using signal 15 successfully."
|
|
733
902
|
% self._process.pid
|
|
734
903
|
)
|
|
735
904
|
break
|
|
736
905
|
except (TypeError,):
|
|
737
|
-
logger.info("
|
|
906
|
+
logger.info("TypeError", exc_info=True)
|
|
738
907
|
pass
|
|
739
908
|
except (PermissionError,):
|
|
740
909
|
logger.info(
|
|
@@ -743,12 +912,45 @@ class Browser:
|
|
|
743
912
|
)
|
|
744
913
|
pass
|
|
745
914
|
except (ProcessLookupError,):
|
|
746
|
-
logger.info("
|
|
915
|
+
logger.info("ProcessLookupError")
|
|
747
916
|
pass
|
|
748
917
|
except (Exception,):
|
|
749
918
|
raise
|
|
750
919
|
self._process = None
|
|
751
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)
|
|
752
954
|
|
|
753
955
|
def quit(self):
|
|
754
956
|
self.stop()
|
|
@@ -780,7 +982,7 @@ class CookieJar:
|
|
|
780
982
|
"""
|
|
781
983
|
connection = None
|
|
782
984
|
for _tab in self._browser.tabs:
|
|
783
|
-
if
|
|
985
|
+
if getattr(_tab, "closed", None):
|
|
784
986
|
continue
|
|
785
987
|
connection = _tab
|
|
786
988
|
break
|
|
@@ -810,7 +1012,7 @@ class CookieJar:
|
|
|
810
1012
|
"""
|
|
811
1013
|
connection = None
|
|
812
1014
|
for _tab in self._browser.tabs:
|
|
813
|
-
if
|
|
1015
|
+
if getattr(_tab, "closed", None):
|
|
814
1016
|
continue
|
|
815
1017
|
connection = _tab
|
|
816
1018
|
break
|
|
@@ -837,7 +1039,7 @@ class CookieJar:
|
|
|
837
1039
|
save_path = pathlib.Path(file).resolve()
|
|
838
1040
|
connection = None
|
|
839
1041
|
for _tab in self._browser.tabs:
|
|
840
|
-
if
|
|
1042
|
+
if getattr(_tab, "closed", None):
|
|
841
1043
|
continue
|
|
842
1044
|
connection = _tab
|
|
843
1045
|
break
|
|
@@ -883,7 +1085,7 @@ class CookieJar:
|
|
|
883
1085
|
included_cookies = []
|
|
884
1086
|
connection = None
|
|
885
1087
|
for _tab in self._browser.tabs:
|
|
886
|
-
if
|
|
1088
|
+
if getattr(_tab, "closed", None):
|
|
887
1089
|
continue
|
|
888
1090
|
connection = _tab
|
|
889
1091
|
break
|
|
@@ -906,7 +1108,7 @@ class CookieJar:
|
|
|
906
1108
|
"""
|
|
907
1109
|
connection = None
|
|
908
1110
|
for _tab in self._browser.tabs:
|
|
909
|
-
if
|
|
1111
|
+
if getattr(_tab, "closed", None):
|
|
910
1112
|
continue
|
|
911
1113
|
connection = _tab
|
|
912
1114
|
break
|