Инструмент 5: "Танк" (Headless Browser Automation)
Стек: Playwright (Async), Selectolax (Гибридный подход).
Суть: Запускаем реальный движок Chromium (без окна). Он выполняет весь JS, рендерит React/Vue компоненты.
Главная фишка архитектора: Мы используем браузер ТОЛЬКО для рендеринга и действий (клик, скролл). Как только контент появился, мы забираем HTML (page.content()) и парсим его через Selectolax. Это в 100 раз быстрее, чем спрашивать текст каждого элемента через API браузера.
Где применять: Сложные SPA, сайты с бесконечным скроллом, сайты, где контент появляется только после клика.
Установка:pip install playwright selectolaxplaywright install chromium
import asyncio
from playwright.async_api import async_playwright, Page, BrowserContext
from selectolax.parser import HTMLParser
from typing import List
# --- 1. CONFIG ---
# Блокируем мусор, чтобы ускорить загрузку в 5 раз
BLOCKED_RESOURCES = [".png", ".jpg", ".jpeg", ".gif", ".svg", ".css", ".woff", ".woff2"]
# --- 2. PARSER CLASS ---
class BrowserWorker:
def __init__(self):
self.playwright = None
self.browser = None
async def start(self):
"""Запуск тяжелого процесса (делаем 1 раз)"""
self.playwright = await async_playwright().start()
# headless=False если хочешь видеть глазами, что происходит
self.browser = await self.playwright.chromium.launch(headless=True)
async def stop(self):
if self.browser:
await self.browser.close()
if self.playwright:
await self.playwright.stop()
async def _configure_page(self, context: BrowserContext) -> Page:
"""Настройка страницы: перехват картинок и таймауты"""
page = await context.new_page()
# Блокировка картинок и шрифтов (Экономия трафика и памяти)
async def route_handler(route):
if any(ext in route.request.url for ext in BLOCKED_RESOURCES):
await route.abort()
else:
await route.continue_()
await page.route("**/*", route_handler)
return page
async def parse_dynamic_page(self, url: str):
print(f"🚜 Танк выехал на: {url}")
# Создаем изолированный контекст (как инкогнито вкладка)
# Тут можно задать user_agent, viewport, proxy
context = await self.browser.new_context(
user_agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64)..."
)
page = await self._configure_page(context)
try:
# 1. Переход
await page.goto(url, wait_until="domcontentloaded", timeout=30000)
# 2. Действия (Логика "Человека")
# Например, ждем появления списка товаров
# Селектор должен быть уникальным для контента
try:
await page.wait_for_selector("div.product-card", timeout=10000)
except Exception:
print("⚠️ Товары не появились. Возможно, сайт лагает или защита.")
return
# Пример: Скроллим вниз, чтобы подгрузить Lazy Load
for _ in range(3):
await page.mouse.wheel(0, 5000)
await asyncio.sleep(1) # Даем JS время на подгрузку
# 3. ГИБРИДНЫЙ ПАРСИНГ (Самый сок)
# Не перебираем элементы через await page.locator(...). Это медленно!
# Забираем весь HTML строкой и отдаем Selectolax.
html = await page.content()
self._parse_with_selectolax(html)
except Exception as e:
print(f"💀 Авария танка: {e}")
finally:
# Обязательно закрываем контекст, чтобы очистить RAM
await context.close()
def _parse_with_selectolax(self, html: str):
"""Быстрый парсинг статики"""
tree = HTMLParser(html)
products = tree.css("div.product-card")
print(f"✅ Найдено элементов: {len(products)}")
for node in products:
title = node.css_first(".title").text(strip=True)
print(f" - {title}")
# --- 3. ENTRY ---
async def main():
worker = BrowserWorker()
await worker.start()
try:
await worker.parse_dynamic_page("<https://example-spa-shop.com>")
finally:
await worker.stop()
if __name__ == "__main__":
asyncio.run(main())
Куда смотреть:
BLOCKED_RESOURCES+page.route: Это критически важно. Без этого Playwright будет качать рекламные баннеры по 5 Мб. Твой парсер ускорится в 3-5 раз благодаря этим строкам.wait_until="domcontentloaded": Мы не ждем полной загрузки (networkidle), иначе будем висеть вечно из-за какой-нибудь метрики. Ждем только DOM, а нужные элементы ждем черезwait_for_selector.- Гибрид: Обрати внимание, я не использую методы Playwright для извлечения текста. Я забираю HTML и паршу его локально. Это Best Practice для высокой производительности.