Coverage for human_requests/browsers/families/patchright_family.py: 92%

39 statements  

« prev     ^ index     » next       coverage.py v7.10.6, created at 2025-09-13 21:41 +0000

1from __future__ import annotations 

2 

3from typing import Any, Dict, Optional 

4 

5from playwright.async_api import Browser 

6 

7from .base import BrowserFamily, DesiredConfig, Family 

8 

9 

10class PatchrightFamily(BrowserFamily): 

11 """ 

12 Patchright — drop-in replacement for Playwright, supports only Chromium. 

13 Stealth is NOT needed/allowed (it is already built-in). 

14 """ 

15 

16 def __init__(self) -> None: 

17 self._pw: Any | None = None 

18 self._browser: Any | None = None 

19 

20 # кэш 

21 self._launch_opts_used: Dict[str, Any] | None = None 

22 

23 @property 

24 def name(self) -> Family: 

25 return "patchright" 

26 

27 @property 

28 def browser(self) -> Optional[Browser]: 

29 return self._browser 

30 

31 async def start(self, cfg: DesiredConfig) -> None: 

32 assert cfg.family == "patchright", "wrong family for PatchrightFamily" 

33 if cfg.stealth: 

34 raise RuntimeError("stealth is incompatible with engine='patchright'.") 

35 

36 need_relaunch = ( 

37 self._pw is None or self._browser is None or self._launch_opts_used != cfg.launch_opts 

38 ) 

39 if need_relaunch: 

40 await self.close() # мягко закрыть, если уже есть 

41 

42 try: 

43 from patchright.async_api import async_playwright as async_patchright 

44 except Exception: 

45 raise RuntimeError( 

46 "engine='patchright', but the 'patchright' package is not installed. " 

47 "Install it with: pip install patchright" 

48 ) 

49 

50 self._pw = await async_patchright().__aenter__() 

51 launcher = self._pw.chromium 

52 

53 kwargs = dict(cfg.launch_opts) 

54 self._browser = await launcher.launch(**kwargs) 

55 

56 self._launch_opts_used = dict(cfg.launch_opts) 

57 

58 async def close(self) -> None: 

59 if self._browser is not None: 

60 await self._browser.close() 

61 self._browser = None 

62 if self._pw is not None: 

63 await self._pw.stop() 

64 self._pw = None 

65 

66 self._launch_opts_used = None