import re from collections.abc import Awaitable, Callable from typing import Any from marketing_intelligence.browser.base import BrowserAdapter, PageSnapshot from marketing_intelligence.core.config import settings def _proxy_args(proxy: dict | None) -> list[str]: """Convert proxy dict to Chrome CLI args (IP-whitelisted, no auth needed).""" if not proxy: return [] server = proxy.get("server", "") return [f"--proxy-server={server}"] if server else [] class NoDriverAdapter(BrowserAdapter): """ nodriver (Chrome, no WebDriver detection). Expects IP-whitelisted proxy — no credential auth support in Chrome CLI. fetch_interactive not supported — use PlaywrightAdapter for scrape_video. """ async def fetch_with_scroll( self, url: str, scroll_distance: int = 3000 ) -> PageSnapshot: import nodriver as uc browser = await uc.start( headless=settings.browser_headless, browser_args=_proxy_args(self.proxy), ) try: tab = await browser.get(url) await self.behavior.human_delay(base=5.0, variance=2.0) await self._scroll(tab, scroll_distance) await self.behavior.human_delay(base=2.0, variance=1.0) html = await tab.get_content() finally: browser.stop() title_m = re.search(r"([^<]+)", html) return PageSnapshot( url=url, html=html, title=title_m.group(1) if title_m else None ) async def fetch_interactive( self, url: str, callback: Callable[[Any, str, str, int], Awaitable[Any]], ) -> Any: raise NotImplementedError( "NoDriverAdapter does not support fetch_interactive. " "Use engine='camoufox' or engine='chromium' for scrape_video." ) async def _scroll(self, tab: Any, distance: int) -> None: import random if self.behavior.human: steps = random.randint(2, 4) per_step = distance // steps for _ in range(steps): jitter = random.randint(-100, 100) await tab.scroll_down(per_step + jitter) await tab.sleep(random.uniform(0.2, 0.7) * self.behavior.delay_factor) else: await tab.scroll_down(distance)