11from __future__ import annotations
22
3- import os
3+ from collections import defaultdict
44from dataclasses import dataclass , field
55from typing import Any
66
1212 HumanPage ,
1313 api_child_field ,
1414)
15+ from human_requests .network_analyzer .anomaly_sniffer import (
16+ HeaderAnomalySniffer ,
17+ WaitHeader ,
18+ WaitSource ,
19+ )
1520from human_requests .abstraction import FetchResponse , HttpMethod , Proxy
1621from playwright .async_api import TimeoutError as PWTimeoutError
1722
@@ -31,6 +36,8 @@ class ChizhikAPI(ApiParent):
3136 """Время ожидания ответа от сервера в миллисекундах."""
3237 headless : bool = True
3338 """Запускать браузер в headless режиме?"""
39+ test_mode : bool = False
40+ """Режим тестирования предполагает более глубокий _warmup который не требуется для обычного использования"""
3441 proxy : str | dict | Proxy | None = field (default_factory = Proxy .from_env )
3542 """Прокси-сервер для всех запросов (если нужен). По умолчанию берет из окружения (если есть).
3643 Принимает как формат Playwright, так и строчный формат."""
@@ -51,6 +58,11 @@ class ChizhikAPI(ApiParent):
5158 page : HumanPage = field (init = False , repr = False )
5259 """Внутренний страница сессии браузера"""
5360
61+ unstandard_headers : dict [str , str ] = field (init = False , repr = False )
62+ """Список нестандартных заголовков пойманных при инициализации"""
63+ unstandard_urls : dict [str , list [str ]] = field (init = False , repr = False )
64+ """Список нестандартных заголовков пойманных при инициализации"""
65+
5466 Geolocation : ClassGeolocation = api_child_field (ClassGeolocation )
5567 """API для работы с геолокацией."""
5668 Catalog : ClassCatalog = api_child_field (ClassCatalog )
@@ -74,30 +86,43 @@ async def _warmup(self) -> None:
7486 proxy = px .as_dict (),
7587 ** self .browser_opts ,
7688 block_images = True ,
89+ i_know_what_im_doing = True ,
7790 ).start ()
7891
7992 self .session = HumanBrowser .replace (br )
8093 self .ctx = await self .session .new_context ()
8194 self .page = await self .ctx .new_page ()
8295 self .page .on_error_screenshot_path = "screenshot.png"
96+
97+ if self .test_mode :
98+ sniffer = HeaderAnomalySniffer (
99+ include_subresources = True , # или False, если интересны только документы
100+ url_filter = lambda u : u .startswith (self .CATALOG_URL ),
101+ )
102+ await sniffer .start (self .ctx )
103+
104+ await self .page .goto (self .MAIN_SITE_URL , wait_until = "networkidle" )
105+ await self .page .wait_for_selector ("next-route-announcer" , state = "attached" )
106+
107+ result_sniffer = await sniffer .complete ()
108+
109+ # Результат: {заголовок: [уникальные значения]}
110+ result = defaultdict (set )
111+
112+ # Проходим по всем URL в 'request'
113+ for _url , headers in result_sniffer ["request" ].items ():
114+ for header , values in headers .items ():
115+ result [header ].update (values ) # добавляем значения, set уберёт дубли
116+
117+ # Преобразуем set обратно в list
118+ self .unstandard_headers = {k : list (v )[0 ] for k , v in result .items ()}
119+ self .unstandard_urls = result_sniffer ["request" ]
120+
83121 await self .page .goto (self .CATALOG_URL , wait_until = "networkidle" )
84122
85- ok = False
86- try_count = 3
87- while not ok and try_count > 0 :
88- try_count -= 1
89- try :
90- await self .page .wait_for_selector (
91- "pre" , timeout = self .timeout_ms , state = "attached"
92- )
93- ok = True
94- except PWTimeoutError :
95- await self .page .reload ()
96- if not ok :
97- raise RuntimeError (await self .page .content ())
98-
99- # await self.page.wait_for_load_state("networkidle")
100- # await asyncio.sleep(3)
123+ await self .page .wait_for_selector (
124+ "pre" , timeout = self .timeout_ms , state = "attached"
125+ )
101126
102127 async def __aexit__ (self , * exc ):
103128 """Выход из контекстного менеджера с закрытием сессии."""
0 commit comments