From 6b77f3bcc3532f32e8a5524b6a9fb266f07df110 Mon Sep 17 00:00:00 2001 From: Jerry Yan <792602257@qq.com> Date: Sun, 16 Aug 2026 23:31:59 +0800 Subject: [PATCH] probe search latency --- scripts/probe_search_latency.py | 73 +++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 scripts/probe_search_latency.py diff --git a/scripts/probe_search_latency.py b/scripts/probe_search_latency.py new file mode 100644 index 0000000..343e87f --- /dev/null +++ b/scripts/probe_search_latency.py @@ -0,0 +1,73 @@ +"""搜索页抓取延迟探针:复现线上 ~5s 的慢请求,定位耗时阶段 + +测量: +1. 首次抓取的 预热耗时 / 目标页耗时 +2. 同会话连续抓取的稳态耗时(预热复用是否生效) +3. 对比「无预热直连」的耗时(验证 Akamai 限速行为是否变化) +""" +from __future__ import annotations + +import asyncio +import sys +import time +from pathlib import Path + +sys.path.insert(0, str(Path(__file__).resolve().parent.parent)) + +from app.shared.config import get_settings # noqa: E402 +from app.scraping.services.browser_fallback import BrowserFallback # noqa: E402 +from app.scraping.services.site_session import SiteSession # noqa: E402 +from app.scraping.core import site # noqa: E402 + +URL = "https://search.rakuten.co.jp/search/mall/kitty/?p=2" + + +async def main() -> int: + settings = get_settings() + print(f"proxy={bool(settings.proxy_server)} timeout={settings.request_timeout_seconds} " + f"ttl={settings.session_ttl_seconds} attempts={settings.http_max_attempts}") + + session = SiteSession(settings, BrowserFallback(settings)) + await session.start() + profile = session._profiles["pc"] + + # 1) 首次抓取(含预热) + t0 = time.monotonic() + await session._ensure_warm(profile) + t_warm = time.monotonic() - t0 + print(f"[1] 预热: {t_warm:.2f}s cookies={sorted(profile.cookie_names & set(site.AKAMAI_COOKIE_NAMES))}") + + t0 = time.monotonic() + page = await session.fetch_html(URL, mobile=False) + t_first = time.monotonic() - t0 + print(f"[1] 首次抓取: {t_first:.2f}s html={len(page)}") + + # 2) 稳态:同会话连抓 3 次 + for i in range(2, 5): + t0 = time.monotonic() + page = await session.fetch_html(URL, mobile=False) + print(f"[{i}] 稳态抓取: {time.monotonic() - t0:.2f}s html={len(page)}") + + await session.close() + + # 3) 对照:全新客户端、无预热、直接打目标页(Akamai 限速基线) + import httpx + from app.shared.proxy import httpx_client_options + + async with httpx.AsyncClient( + headers=site.default_headers(mobile=False), + timeout=settings.request_timeout_seconds, + follow_redirects=True, + http2=True, + **httpx_client_options(settings), + ) as cold: + t0 = time.monotonic() + resp = await cold.get(URL) + print(f"[对照] 无预热直连: {time.monotonic() - t0:.2f}s status={resp.status_code} " + f"html={len(resp.text)} cookies={sorted(c for c in resp.cookies.keys())}") + + return 0 + + +if __name__ == "__main__": + raise SystemExit(asyncio.run(main()))