losander

NetworkIdleWaiter

Nov 8th, 2025
214
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 5.23 KB | Source Code | 0 0
  1. import asyncio
  2. from collections import deque
  3. from datetime import datetime
  4. import time
  5. from playwright.async_api import Page
  6.  
  7.  
  8. class NetworkIdleWaiter:
  9.     """
  10.    Класс для продвинутого ожидания.
  11.  
  12.    Запускает таймер и сбрасывает его после каждого загруженного файла.
  13.    Спустя заданное время после последней активности разблокирует поток.
  14.    """
  15.     def __init__(
  16.             self,
  17.             page: Page,
  18.             idle_time: float = 1.0,
  19.             timeout: float = 10.0,
  20.             ignore_resources: list = None,
  21.             print_on: bool = False,
  22.     ):
  23.         self.page = page
  24.         self.idle_time = idle_time
  25.         self.timeout = timeout
  26.         self.ignore_resources = ignore_resources or ['font', 'websocket']
  27.  
  28.         self.pending_requests = {}
  29.         self.last_activity = time.time()
  30.         self.network_log = deque(maxlen=100)  # Последние 100 запросов для отладки
  31.  
  32.         self.print_on = print_on
  33.  
  34.     async def wait(self):
  35.         """Ждет пока сеть станет неактивной"""
  36.  
  37.         # Подписываемся на события
  38.         self.page.on("request", self._on_request)
  39.         self.page.on("response", self._on_response)
  40.         self.page.on("requestfailed", self._on_request_failed)
  41.  
  42.         start_time = time.time()
  43.  
  44.         try:
  45.             while True:
  46.                 await asyncio.sleep(0.1)
  47.  
  48.                 current_time = time.time()
  49.                 idle_duration = current_time - self.last_activity
  50.  
  51.                 # Проверяем условия выхода
  52.                 if len(self.pending_requests) == 0 and idle_duration >= self.idle_time:
  53.                     if self.print_on:
  54.                         print(f"✅ Сеть неактивна {idle_duration:.1f} сек. "
  55.                               f"Загрузка завершена!")
  56.                     break
  57.  
  58.                 # Проверка таймаута
  59.                 if current_time - start_time > self.timeout:
  60.                     if self.print_on:
  61.                         print(f"⚠️ Таймаут {self.timeout} сек. "
  62.                               f"Остались запросы: {len(self.pending_requests)}")
  63.                         if self.pending_requests:
  64.                             print("Незавершенные запросы:")
  65.                             for url, info in list(self.pending_requests.items())[:5]:
  66.                                 print(f"  - {info['type']}: {url[:100]}...")
  67.                     break
  68.  
  69.                 # Отладочная информация
  70.                 if self.print_on:
  71.                     if len(self.pending_requests) > 0:
  72.                         print(f"⏳ Ожидание... Активных запросов: {len(self.pending_requests)}, "
  73.                               f"Idle: {idle_duration:.1f}s")
  74.  
  75.         finally:
  76.             # Отписываемся от событий
  77.             self.page.remove_listener("request", self._on_request)
  78.             self.page.remove_listener("response", self._on_response)
  79.             self.page.remove_listener("requestfailed", self._on_request_failed)
  80.  
  81.     def get_stats(self):
  82.         """Получить статистику по сетевой активности"""
  83.         return {
  84.             'total_requests': len(self.network_log),
  85.             'pending': len(self.pending_requests),
  86.             'last_activity': self.last_activity,
  87.             'log': list(self.network_log)
  88.         }
  89.  
  90.     # Обработчики событий
  91.     def _on_request(self, request):
  92.         # Игнорируем определенные типы ресурсов
  93.         if request.resource_type in self.ignore_resources:
  94.             return
  95.  
  96.         self.pending_requests[request.url] = {
  97.             'start': time.time(),
  98.             'type': request.resource_type,
  99.             'method': request.method
  100.         }
  101.         self.last_activity = time.time()
  102.  
  103.         self.network_log.append({
  104.             'event': 'request',
  105.             'url': request.url,
  106.             'type': request.resource_type,
  107.             'time': datetime.now().isoformat()
  108.         })
  109.  
  110.     def _on_response(self, response):
  111.         if response.url in self.pending_requests:
  112.             request_info = self.pending_requests.pop(response.url)
  113.             duration = time.time() - request_info['start']
  114.  
  115.             self.network_log.append({
  116.                 'event': 'response',
  117.                 'url': response.url,
  118.                 'status': response.status,
  119.                 'duration': duration,
  120.                 'time': datetime.now().isoformat()
  121.             })
  122.  
  123.         self.last_activity = time.time()
  124.  
  125.     def _on_request_failed(self, request):
  126.         if request.url in self.pending_requests:
  127.             self.pending_requests.pop(request.url)
  128.  
  129.             self.network_log.append({
  130.                 'event': 'failed',
  131.                 'url': request.url,
  132.                 'failure': request.failure,
  133.                 'time': datetime.now().isoformat()
  134.             })
  135.  
  136.         self.last_activity = time.time()
  137.  
Advertisement
Add Comment
Please, Sign In to add comment