Purpose
Open a county-taxes.net property-tax lookup form, confirm that the usable fields have rendered after any anti-bot challenge, perform an address or parcel lookup including autocomplete selection when required, and optionally inspect the returned tax-bill details.
When to Use
Use when the caller needs to inspect, document, or use a county-taxes.net property-tax lookup form or view the details returned for a parcel, especially when the page is protected by Cloudflare Turnstile or requires selecting an autocomplete suggestion before displaying the property record.
Workflow
- Construct the direct page URL using
https://county-taxes.net/{county-slug}/property-taxand navigate with page-load waiting. For San Francisco, usehttps://county-taxes.net/ca-sanfrancisco/property-tax. - Allow the page to settle after navigation. If a Cloudflare challenge is present, invoke the browser's Cloudflare solver. Wait for the challenge and page content to settle; if it remains, invoke the solver in wait mode and, only if necessary, click challenge controls matching
input[type='checkbox'], .cf-turnstile, #cf-turnstile, [id*='turnstile'], iframe, then wait again. - Confirm that the lookup form controls are visible rather than treating a challenge page as the form. Run this self-contained evaluator on the loaded page:
(() => {
const visible = el => {
const s = getComputedStyle(el), r = el.getBoundingClientRect();
return s.display !== 'none' && s.visibility !== 'hidden' && r.width > 0 && r.height > 0;
};
const text = el => (el?.textContent || '').replace(/\\s+/g, ' ').trim();
return [...document.querySelectorAll('form')].map((form, formIndex) => ({
formIndex,
action: form.action || location.href,
method: (form.method || 'get').toLowerCase(),
fields: [...form.querySelectorAll('input, select, textarea, button')]
.filter(visible)
.map((el, index) => {
const id = el.id;
const label = id ? document.querySelector(`label[for="${CSS.escape(id)}"]`) : el.closest('label');
return {
index,
tag: el.tagName.toLowerCase(),
type: el.getAttribute('type') || null,
name: el.getAttribute('name') || null,
id: id || null,
role: el.getAttribute('role') || null,
ariaLabel: el.getAttribute('aria-label') || null,
placeholder: el.getAttribute('placeholder') || null,
label: text(label),
options: el.tagName === 'SELECT' ? [...el.options].map(o => ({value:o.value, text:text(o)})) : undefined
};
})
}));
})()- For a lookup, fill the visible search control matching
input[placeholder*='block-lot'], input[placeholder*='Bill'], input[type='search'], input[role='combobox']with{property-or-parcel-query}. Wait for the suggestions to populate. This site may require choosing the suggestion rather than submitting the raw text. Inspect and select the first visiblea[role='option']whose normalized text matches or contains{property-or-parcel-query}; if several match, choose the most specific address/parcel suggestion. A visibility-aware autocomplete extractor and selector is:
(() => {
const visible = el => { const s=getComputedStyle(el), r=el.getBoundingClientRect(); return s.display!=='none' && s.visibility!=='hidden' && r.width>0 && r.height>0; };
const clean = el => (el?.textContent || '').replace(/\\s+/g,' ').trim();
const options = [...document.querySelectorAll('a[role="option"], [role="option"]')].filter(visible).map((el,index)=>({index,tag:el.tagName.toLowerCase(),text:clean(el),href:el.href||null,selected:el.getAttribute('aria-selected')||null}));
const query = [...document.querySelectorAll('input[placeholder*="block-lot"], input[placeholder*="Bill"], input[type="search"], input[role="combobox"]')].find(visible)?.value || '';
const normalized = query.toLowerCase().trim();
const match = options.find(o => normalized && o.text.toLowerCase().includes(normalized)) || options[0];
if (match) {
const el = [...document.querySelectorAll('a[role="option"], [role="option"]')].filter(visible)[match.index];
el?.click();
}
return {query, options, selected: match || null};
})()- Wait for the lookup response and any details panel to finish rendering. If no autocomplete option appears, submit by clicking the first visible control matching
[aria-label*=search i], button[type=submit], form button; if none exists, dispatch a bubbling Enter key event on the active input. - If the caller requests the tax-bill details and the returned state exposes a visible link or button whose trimmed text is exactly
View, click it and wait for the details view to load. Do not guess a result URL because no stable post-lookup URL was observed. A runnable visibility-aware click helper is:
(() => {
const visible = el => { const s=getComputedStyle(el), r=el.getBoundingClientRect(); return s.display!=='none' && s.visibility!=='hidden' && r.width>0 && r.height>0; };
const view = [...document.querySelectorAll('a, button')].find(el => visible(el) && /^view$/i.test((el.textContent||'').replace(/\\s+/g,' ').trim()));
if (!view) return {clicked:false};
view.click();
return {clicked:true,text:(view.textContent||'').replace(/\\s+/g,' ').trim()};
})()- Extract the currently rendered lookup/details state in one page evaluation:
(() => {
const visible = el => { const s=getComputedStyle(el), r=el.getBoundingClientRect(); return s.display!=='none' && s.visibility!=='hidden' && r.width>0 && r.height>0; };
const clean = v => (v||'').replace(/\\s+/g,' ').trim();
const options = [...document.querySelectorAll('a[role="option"], [role="option"]')].filter(visible).map(el=>({text:clean(el.textContent),href:el.href||null,selected:el.getAttribute('aria-selected')||null}));
const fields = [...document.querySelectorAll('input, select, textarea')].filter(visible).map(el=>({name:el.name||null,id:el.id||null,value:el.value||'',placeholder:el.getAttribute('placeholder')||null}));
const rows = [...document.querySelectorAll('table tr, dl, .detail, [class*="detail"], [class*="tax"]')].filter(visible).map(el=>({text:clean(el.textContent),cells:[...el.querySelectorAll(':scope > th, :scope > td, :scope > dt, :scope > dd')].map(x=>clean(x.textContent)).filter(Boolean)})).filter(x=>x.text);
return {url:location.href,title:clean(document.title),fields,autocompleteOptions:options,details:rows};
})()- Capture any requested screenshot only after the form is rendered, after the autocomplete result loads, or after the tax-bill details finish loading. Batch navigation, challenge handling, input, suggestion selection, optional
View, extraction, and screenshot capture where the browser interface permits.
Site-Specific Gotchas
- The direct property-tax route is
/ca-sanfrancisco/property-taxfor San Francisco; county slugs use the{state}{county}pattern shown by this route. - The site may remain behind Cloudflare after initial navigation. Allow the solver to complete before inspecting or submitting; the challenge can require an additional wait-mode solve and interaction with a Turnstile checkbox or iframe.
- Do not treat a challenge page as the lookup form. Confirm that property-tax form controls are visible before capturing the screenshot or running the evaluator.
- The lookup input is exposed by a placeholder containing
block-lotorBill, or as a search input/combobox. Submission may require an explicit search/submit button, but the observed San Francisco flow requires waiting for and clicking an autocomplete option matching the entered parcel or address. - Returned lookup results may require an explicit
Viewlink or button before the tax-bill details are displayed. Match the visible control by text rather than assuming a result URL or opaque identifier. - No stable result-page URL or result-row structure was observed; the selected autocomplete result can leave the browser on the same property-tax route. Do not guess a direct post-lookup URL. Use the current-page evaluator after the response settles.
- Raw detail selectors such as
[class*="detail"]and[class*="tax"]are fallback selectors and may include container text; prefer the returnedcellsor confirmed labels when presenting structured tax fields.
Expected Output
A screenshot showing the rendered county property-tax lookup form, the autocomplete result state, or the returned tax-bill details, depending on the request. Include the form evaluator's array of forms and visible controls when form inspection is requested, the submitted query and selected autocomplete option when a lookup is performed, and the current URL plus extracted visible detail rows after the response finishes loading. Extract result details only from selectors confirmed on the returned page.