Cache postcodes

This commit is contained in:
Andras Schmelczer 2026-06-14 14:50:38 +01:00
parent f59d01227b
commit 8e4c56bb0d
7 changed files with 502 additions and 141 deletions

View file

@ -29,6 +29,7 @@ from urllib.parse import parse_qsl, urlencode, urljoin, urlparse, urlunparse
import httpx
import shutdown
from constants import (
DATA_DIR,
DELAY_BETWEEN_PAGES,
@ -973,7 +974,7 @@ def _paginate(
listing["_detail"] = fetch_detail(url)
if not cached:
detail_state["fetched"] += 1
time.sleep(DELAY_BETWEEN_PAGES)
shutdown.sleep(DELAY_BETWEEN_PAGES)
all_listings = _extract_listings(page)
for listing in all_listings:
@ -988,13 +989,15 @@ def _paginate(
page_num = 2
while True:
if shutdown.stop_requested():
break
next_url = _find_next_page_url(page)
if not next_url:
if total_results > 0 and len(all_listings) >= total_results:
break
next_url = _url_with_page(page.url, page_num)
time.sleep(DELAY_BETWEEN_PAGES)
shutdown.sleep(DELAY_BETWEEN_PAGES)
try:
page.goto(next_url, wait_until="domcontentloaded", timeout=30000)
@ -1119,9 +1122,23 @@ def _extract_outcode(text: str) -> str | None:
# listingId -> parsed detail dict (or None). Failures are cached too, so a
# broken listing is not re-fetched within a run (the same listing reappears
# across overlapping outcode searches).
# across overlapping outcode searches). Seeded from / dumped to a persistent
# on-disk cache by the orchestrator (see postcode_cache.py) so a recurring
# scrape only re-fetches newly-listed properties — the biggest saving for
# Zoopla, whose detail fetch drives a real browser tab.
_detail_cache: dict[str, dict | None] = {}
def seed_detail_cache(mapping: dict) -> None:
"""Pre-populate the in-memory detail cache from a persisted snapshot."""
if mapping:
_detail_cache.update(mapping)
def detail_cache_snapshot() -> dict:
"""Return a JSON-serialisable copy of the in-memory detail cache."""
return dict(_detail_cache)
_LISTING_ID_RE = re.compile(r"/details/(\d+)/?")
# The property's own location is carried by a `"location":{...}` wrapper and a