"""scripts/probe_civitek.py — exploratory probe of Civitek OCRS flow. NO production code. Just maps the click sequence + DOM for civitek_ocrs.py. Usage: python scripts/probe_civitek.py """ from __future__ import annotations import sys import time from pathlib import Path def probe(): from playwright.sync_api import sync_playwright out_dir = Path(__file__).parent.parent / "_probe_out" / "civitek" out_dir.mkdir(parents=True, exist_ok=True) with sync_playwright() as p: browser = p.chromium.launch(headless=True) context = browser.new_context( user_agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Chrome/120", ) page = context.new_page() # STEP 1: County entry page (Hernando = 27) print("[1] GET county entry page...") page.goto("https://www.civitekflorida.com/ocrs/county/27/", wait_until="networkidle") print(f" Title: {page.title()}") print(f" URL: {page.url}") (out_dir / "01_entry.html").write_text(page.content(), encoding="utf-8") # STEP 2: Click "Public" button print("\n[2] Click 'Public' button...") public_btn = page.locator("button:has-text('Public')").first print(f" Public button visible: {public_btn.is_visible()}") public_btn.click() page.wait_for_timeout(3000) # JSF AJAX settle print(f" After click URL: {page.url}") print(f" After click title: {page.title()}") (out_dir / "02_after_public.html").write_text(page.content(), encoding="utf-8") # STEP 3: Look for disclaimer / accept body_text = page.inner_text("body")[:2000] print(f"\n[3] Page body snippet (first 800 chars):\n{body_text[:800]}") # Check for common disclaimer button names for txt in ["Accept", "I Accept", "I Agree", "Agree", "Continue"]: loc = page.locator(f"button:has-text('{txt}'), input[type=submit][value*='{txt}']") count = loc.count() if count > 0: print(f" Found '{txt}' button: {count} match(es)") # STEP 4: Look for search form fields print("\n[4] Form fields on current page:") inputs = page.locator("input").all() for i, inp in enumerate(inputs[:30]): try: name = inp.get_attribute("name") or "" type_ = inp.get_attribute("type") or "" value = (inp.get_attribute("value") or "")[:30] placeholder = inp.get_attribute("placeholder") or "" if type_ in ("hidden",) and not name.startswith("javax"): continue if type_ == "hidden": continue print(f" [{i}] name={name!r} type={type_!r} value={value!r} placeholder={placeholder!r}") except Exception as e: print(f" [{i}] error: {e}") print("\n[5] Buttons on page:") buttons = page.locator("button, input[type=submit]").all() for i, btn in enumerate(buttons[:15]): try: txt = (btn.inner_text() or btn.get_attribute("value") or "").strip()[:50] btn_id = btn.get_attribute("id") or "" print(f" [{i}] text={txt!r} id={btn_id!r}") except Exception: pass # Snapshot page.screenshot(path=str(out_dir / "02_after_public.png"), full_page=True) # STEP 6: Click "I Agree" disclaimer print("\n[6] Click 'I Agree'...") agree = page.locator("button:has-text('I Agree')").first if agree.count() > 0: agree.click() page.wait_for_timeout(3000) # JSF AJAX settle print(f" After agree URL: {page.url}") (out_dir / "03_after_agree.html").write_text(page.content(), encoding="utf-8") page.screenshot(path=str(out_dir / "03_after_agree.png"), full_page=True) print("\n[7] Search form fields after disclaimer:") for inp in page.locator("input, select").all()[:40]: try: tag = inp.evaluate("el => el.tagName.toLowerCase()") name = inp.get_attribute("name") or "" type_ = inp.get_attribute("type") or "" id_ = inp.get_attribute("id") or "" placeholder = inp.get_attribute("placeholder") or "" label_for = "" if id_: lbl = page.locator(f"label[for='{id_}']").first if lbl.count() > 0: label_for = lbl.inner_text()[:50] if type_ == "hidden": continue print(f" <{tag}> id={id_!r} name={name!r} type={type_!r} placeholder={placeholder!r} label={label_for!r}") except Exception: pass print("\n[8] Buttons after disclaimer:") for btn in page.locator("button, input[type=submit]").all()[:20]: try: txt = (btn.inner_text() or btn.get_attribute("value") or "").strip()[:50] btn_id = btn.get_attribute("id") or "" print(f" text={txt!r} id={btn_id!r}") except Exception: pass print("\n[9] Links / nav after disclaimer (first 20):") for a in page.locator("a").all()[:20]: try: txt = (a.inner_text() or "").strip()[:60] href = a.get_attribute("href") or "" if txt: print(f" {txt!r} → {href[:80]}") except Exception: pass print(f"\n[OK] Screenshots and HTML saved to {out_dir}/") browser.close() if __name__ == "__main__": try: probe() except Exception as e: import traceback print(f"ERROR: {e}", file=sys.stderr) traceback.print_exc() sys.exit(1)