"""Find the JSON API endpoint that bcpa.net's JS calls to populate property data.""" from pathlib import Path import json def probe(): from playwright.sync_api import sync_playwright out_dir = Path(__file__).parent.parent / "_probe_out" / "bcpa" folio = "484226062150" json_responses = [] all_xhr = [] with sync_playwright() as p: browser = p.chromium.launch(headless=True) ctx = browser.new_context( user_agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Chrome/131.0.0.0 Safari/537.36", ) page = ctx.new_page() def on_response(resp): try: u = resp.url if any(x in u for x in (".css", ".png", ".jpg", ".woff", ".ico", ".gif", "google", "fonts.")): return ct = resp.headers.get("content-type", "") all_xhr.append({"url": u[:200], "status": resp.status, "ct": ct}) if "json" in ct.lower(): try: body = resp.text() json_responses.append({ "url": u, "status": resp.status, "body_preview": body[:500], "body_full": body, }) except Exception: pass except Exception: pass page.on("response", on_response) # Try the SPA URL (which we know loads data) spa_url = f"https://web.bcpa.net/bcpaclient/#/Record-Search?folio={folio}" print(f"[1] Loading SPA: {spa_url}") page.goto(spa_url, wait_until="domcontentloaded", timeout=30000) page.wait_for_timeout(15000) print(f"\n[2] All XHR/network responses captured ({len(all_xhr)}):") for r in all_xhr: if any(x in r["ct"] for x in ("json", "xml", "html")): print(f" {r['status']} [{r['ct'][:30]}] {r['url'][:130]}") print(f"\n[3] JSON responses found: {len(json_responses)}") for jr in json_responses: print(f"\n URL: {jr['url']}") print(f" Status: {jr['status']}") print(f" Preview: {jr['body_preview']}") # Save full JSON responses if json_responses: (out_dir / "json_responses.json").write_text( json.dumps(json_responses, indent=2), encoding="utf-8" ) # Also try directly hitting common ASP.NET WebMethod endpoints print(f"\n[4] Probing common WebMethod endpoint patterns directly:") candidates = [ f"https://web.bcpa.net/bcpaclient/search.aspx/getOwnerInfo", f"https://web.bcpa.net/bcpaclient/search.aspx/getPropertyData", f"https://web.bcpa.net/bcpaclient/search.aspx/getRecordByFolio", f"https://web.bcpa.net/bcpaclient/search.aspx/GetRecordByFolio", ] for url_test in candidates: try: resp = page.request.post(url_test, data=json.dumps({"folioNumber": folio}), headers={"Content-Type": "application/json"}) ct = resp.headers.get("content-type", "") body = (resp.text())[:200] print(f" POST {url_test}: {resp.status} [{ct[:30]}] body={body!r}") except Exception as e: print(f" POST {url_test}: ERROR {e}") browser.close() print(f"\n[OK] saved to {out_dir}/") if __name__ == "__main__": probe()