92 lines
3.5 KiB
Python
92 lines
3.5 KiB
Python
"""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()
|