92 行
3.7 KiB
Python
92 行
3.7 KiB
Python
from __future__ import annotations
|
|
|
|
from pathlib import Path
|
|
from typing import Any, Dict, List
|
|
|
|
from lab.utils import ensure_dir, write_json
|
|
|
|
|
|
def capture(url: str, run_dir: Path, prefix: str = "baseline") -> Dict[str, Any]:
|
|
payload: Dict[str, Any] = {
|
|
"required": True,
|
|
"present": False,
|
|
"refs": [],
|
|
"reason": "playwright runtime unavailable",
|
|
"error_kind": "import-error",
|
|
}
|
|
try:
|
|
from playwright.sync_api import sync_playwright # type: ignore
|
|
except Exception as exc:
|
|
payload["reason"] = f"playwright import failed: {exc}"
|
|
write_json(run_dir / "logs" / f"{prefix}-browser.json", payload)
|
|
return payload
|
|
|
|
assets_dir = run_dir / "assets"
|
|
ensure_dir(assets_dir)
|
|
screenshot_path = assets_dir / f"{prefix}.png"
|
|
dom_path = assets_dir / f"{prefix}-dom.html"
|
|
console_path = run_dir / "logs" / f"{prefix}-console.json"
|
|
network_path = run_dir / "logs" / f"{prefix}-network.json"
|
|
page_path = run_dir / "logs" / f"{prefix}-page.json"
|
|
console_messages: List[Dict[str, Any]] = []
|
|
requests_seen: List[Dict[str, Any]] = []
|
|
page_title = ""
|
|
page_body_excerpt = ""
|
|
final_url = url
|
|
try:
|
|
with sync_playwright() as p:
|
|
try:
|
|
browser = p.chromium.launch(headless=True)
|
|
except Exception as exc:
|
|
payload["reason"] = f"chromium launch failed: {exc}"
|
|
payload["error_kind"] = "launch-failed"
|
|
write_json(run_dir / "logs" / f"{prefix}-browser.json", payload)
|
|
return payload
|
|
page = browser.new_page()
|
|
page.on("console", lambda msg: console_messages.append({"type": msg.type, "text": msg.text}))
|
|
page.on("request", lambda req: requests_seen.append({"method": req.method, "url": req.url}))
|
|
response = page.goto(url, wait_until="networkidle", timeout=20000)
|
|
if response is None:
|
|
payload["reason"] = "page navigation returned no response"
|
|
payload["error_kind"] = "navigation-failed"
|
|
browser.close()
|
|
write_json(run_dir / "logs" / f"{prefix}-browser.json", payload)
|
|
return payload
|
|
if response.status >= 500:
|
|
payload["reason"] = f"page returned {response.status}"
|
|
payload["error_kind"] = "target-5xx"
|
|
browser.close()
|
|
write_json(run_dir / "logs" / f"{prefix}-browser.json", payload)
|
|
return payload
|
|
page.screenshot(path=str(screenshot_path), full_page=True)
|
|
dom_path.write_text(page.content(), encoding="utf-8")
|
|
final_url = page.url
|
|
page_title = page.title()
|
|
page_body_excerpt = (page.text_content("body") or "")[:600]
|
|
browser.close()
|
|
except Exception as exc:
|
|
payload["reason"] = str(exc)
|
|
payload["error_kind"] = "target-timeout" if "Timeout" in str(exc) else "navigation-failed"
|
|
write_json(run_dir / "logs" / f"{prefix}-browser.json", payload)
|
|
return payload
|
|
write_json(console_path, console_messages)
|
|
write_json(network_path, requests_seen)
|
|
write_json(
|
|
page_path,
|
|
{
|
|
"url": final_url,
|
|
"title": page_title,
|
|
"body_excerpt": page_body_excerpt,
|
|
},
|
|
)
|
|
payload = {
|
|
"required": True,
|
|
"present": True,
|
|
"page_title": page_title,
|
|
"page_url": final_url,
|
|
"error_kind": None,
|
|
"refs": [str(screenshot_path), str(dom_path), str(console_path), str(network_path), str(page_path)],
|
|
}
|
|
write_json(run_dir / "logs" / f"{prefix}-browser.json", payload)
|
|
return payload
|