"""Probe qPublic Indian River address search with real address from user's deal. Address: 674 30th Ave SW Vero Beach FL 32968 (Zillow MLS deal in screenshot). """ from pathlib import Path def probe(): from playwright.sync_api import sync_playwright out_dir = Path(__file__).parent.parent / "_probe_out" / "qpublic" 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/120", ) page = ctx.new_page() # Capture network POSTs captured = [] page.on("request", lambda r: captured.append({"m": r.method, "url": r.url[:150]}) if r.method == "POST" else None) url = "https://qpublic.schneidercorp.com/Application.aspx?App=IndianRiverCountyFL&PageType=Search" page.goto(url, wait_until="domcontentloaded") page.wait_for_timeout(3000) print(f"[1] Page: {page.title()}") # Dismiss disclaimer/cookie banner if present (the "Agree" we saw) for txt in ["I Agree", "Agree", "Accept All", "Accept"]: loc = page.locator(f"button:has-text('{txt}'), a:has-text('{txt}')").first if loc.count() > 0: try: if loc.is_visible(): print(f"[2] Clicking '{txt}' (likely cookie/disclaimer banner)") loc.click() page.wait_for_timeout(1500) break except Exception: pass # Search by Location Address: txtAddress print("[3] Filling address search...") addr_input_id = "ctlBodyPane_ctl01_ctl01_txtAddress" page.evaluate(f""" const inp = document.getElementById('{addr_input_id}'); inp.focus(); inp.value = '674 30th Ave SW'; inp.dispatchEvent(new Event('input', {{ bubbles: true }})); inp.dispatchEvent(new Event('change', {{ bubbles: true }})); """) page.wait_for_timeout(800) val = page.locator(f"#{addr_input_id}").input_value() print(f" address input value: {val!r}") # The search button is sibling to the address input — find Search button in same section # qPublic uses ASP.NET LinkButton. Find any submit near the address input. # Try the button just after txtAddress in DOM print("[4] Looking for Search button near address input...") search_btn_id = page.evaluate(f""" () => {{ const inp = document.getElementById('{addr_input_id}'); if (!inp) return null; // Find the parent panel/div, then look for a submit-like element let parent = inp.closest('.panel-body, .form-group, fieldset, div'); while (parent) {{ const btn = parent.querySelector('input[type=submit], button[type=submit], a.btn'); if (btn) return btn.id || btn.outerHTML.substring(0, 200); parent = parent.parentElement; }} return null; }} """) print(f" found button: {search_btn_id!r}") # Try the button by clicking the input's parent's Search button # Use a simpler approach: click the button labeled "Search" closest to address input try: # In qPublic, each search section has its own Search button. The one for address # is typically btnSearch right after txtAddress btn = page.locator(f"#ctlBodyPane_ctl01_ctl01_btnSearch") if btn.count() > 0: btn.click() else: # Fallback: find any Search button in the address panel section = page.locator("div:has(#ctlBodyPane_ctl01_ctl01_txtAddress)").first section.locator("input[type=submit], button:has-text('Search')").first.click() page.wait_for_timeout(15000) # longer wait for Cloudflare challenge print(f"[5] After search: URL={page.url[:100]}") except Exception as e: print(f" Search click error: {e}") # Dump body for diagnosis body_full = page.inner_text("body") print(f"\n[5b] Full body text ({len(body_full)} chars):\n{body_full[:2000]}") (out_dir / "02_results.html").write_text(page.content(), encoding="utf-8") page.screenshot(path=str(out_dir / "02_results.png"), full_page=True) # Check for results body = page.inner_text("body") print(f"\n[6] Body length: {len(body)}") # Look for parcel result table or "no results" print("\n[7] Result indicators:") for kw in ["no results", "not found", "no matches", "search results", "parcel"]: cnt = body.lower().count(kw) if cnt: print(f" '{kw}': {cnt} occurrences") # Look for result links result_links = page.locator("a[href*='KeyValue='], a[href*='ParcelID='], a[href*='PageID=']").all() print(f"\n[8] Result links (first 5):") for a in result_links[:5]: try: txt = (a.inner_text() or "").strip()[:80] href = a.get_attribute("href") or "" if txt: print(f" {txt!r}") print(f" href: {href[:120]}") except Exception: pass # Final POSTs check print(f"\n[9] Total POSTs during search: {len(captured)}") for c in captured[-8:]: print(f" {c['m']} {c['url']}") browser.close() if __name__ == "__main__": probe()