← Back to SKILL.md1#!/usr/bin/env python32"""Record a HAR file while driving a website with Playwright.3 4Usage:5 python3 har_capture.py <url> <output.har> [--wait SECONDS] \6 [--action "fill:SELECTOR:TEXT"] [--action "press:SELECTOR:KEY"] \7 [--action "click:SELECTOR"] [--action "goto:URL"] [--action "sleep:SECONDS"]8 9Actions run in order after page load. The HAR embeds request/response bodies10(record_har_content='embed') so derived clients can see payload shapes.11 12NOTE: a failing action raises before the HAR is flushed -- you get no file.13Fix the selector (try --headed to watch) and rerun.14"""15import argparse16import sys17import time18 19from playwright.sync_api import sync_playwright20 21 22def run_action(page, spec: str) -> None:23 parts = spec.split(":", 2)24 kind = parts[0]25 if kind == "fill":26 page.fill(parts[1], parts[2])27 elif kind == "press":28 page.press(parts[1], parts[2])29 elif kind == "click":30 page.click(parts[1])31 elif kind == "goto":32 page.goto(parts[1] + (":" + parts[2] if len(parts) > 2 else ""))33 elif kind == "sleep":34 time.sleep(float(parts[1]))35 else:36 raise ValueError(f"unknown action: {spec}")37 38 39def main() -> int:40 ap = argparse.ArgumentParser()41 ap.add_argument("url")42 ap.add_argument("har_path")43 ap.add_argument("--wait", type=float, default=3.0,44 help="seconds to idle at the end so late XHRs land in the HAR")45 ap.add_argument("--action", action="append", default=[],46 help="fill:SEL:TEXT | press:SEL:KEY | click:SEL | goto:URL | sleep:SECS")47 ap.add_argument("--headed", action="store_true")48 args = ap.parse_args()49 50 with sync_playwright() as p:51 browser = p.chromium.launch(headless=not args.headed)52 context = browser.new_context(53 record_har_path=args.har_path,54 record_har_content="embed", # keep response bodies in the HAR55 )56 page = context.new_page()57 page.goto(args.url, wait_until="domcontentloaded")58 for spec in args.action:59 run_action(page, spec)60 try:61 page.wait_for_load_state("networkidle", timeout=15000)62 except Exception:63 pass # some pages never fully idle; the trailing --wait covers it64 time.sleep(args.wait)65 context.close() # flushes the HAR66 browser.close()67 print(f"HAR written: {args.har_path}")68 return 069 70 71if __name__ == "__main__":72 sys.exit(main())73