HA webhook works, also more makelaars

This commit is contained in:
2026-04-04 01:35:29 +02:00
parent b35025b9cb
commit 8450c33887
4 changed files with 163 additions and 3 deletions

View File

@@ -734,6 +734,128 @@ def fetch_3dmakelaars() -> list[RawListing]:
return listings
# ---------------------------------------------------------------------------
# Dupont ERA Makelaars (Schiedam/Rotterdam)
# ---------------------------------------------------------------------------
_DUPONT_BASE = "https://www.dupont.nl"
_DUPONT_STATUS_MAP = {
"te koop": "beschikbaar",
"nieuw": "beschikbaar",
"onder bod": "onder_bod",
"verkocht onder voorbehoud": "onder_bod",
"verkocht": "verkocht",
}
def _dupont_detail(detail_url: str) -> dict:
"""Fetch Dupont detail page and extract kenmerken from dt/dd pairs."""
try:
soup = fetch_soup(detail_url)
# Parse dt/dd pairs into label → value map
kv: dict[str, str] = {}
dts = soup.select("dt")
dds = soup.select("dd")
for dt, dd in zip(dts, dds):
label = dt.get_text(strip=True).lower()
value = dd.get_text(strip=True)
kv[label] = value
# Extract postcode from small tag (format: "NNNN AA CITY")
postcode = None
small_tag = soup.select_one("section div.container-fluid small")
if small_tag:
postcode = _extract_postcode(small_tag.get_text())
return {
"postcode": postcode,
"woningtype": kv.get("soort woning"),
"bouwjaar": kv.get("bouwjaar"),
"woonoppervlak": kv.get("woonoppervlakte"),
"kamers": kv.get("aantal kamers"),
"slaapkamers": kv.get("aantal slaapkamers"),
"energielabel": kv.get("energielabel"),
}
except Exception as e:
log.warning("dupont: detail fetch fout %s: %s", detail_url, e)
return {}
def fetch_dupont() -> list[RawListing]:
"""Fetch Dupont ERA Makelaars listings with pagination and detail pages."""
listings = []
page = 1
while True:
url = f"{_DUPONT_BASE}/aanbod/koopwoningen?page={page}"
soup = fetch_soup(url)
cards = soup.select("article.object")
if not cards:
break
for card in cards:
try:
# Extract URL
a_tag = card.select_one("a[href]")
if not a_tag or "href" not in a_tag.attrs:
continue
detail_url = a_tag["href"]
if not detail_url.startswith("http"):
detail_url = _DUPONT_BASE + detail_url
# Extract listing-level data
adres = _text(card, "h3")
stad = _text(card, "h4")
prijs_text = _text(card, "div.price")
prijs = parse_prijs(prijs_text)
# Extract status from label
status_label = _text(card, "div.label") or "beschikbaar"
status_label = status_label.strip().lower()
status = _DUPONT_STATUS_MAP.get(status_label, "beschikbaar")
# Extract image
img_tag = card.select_one("img.img-responsive")
hero = img_tag["src"] if img_tag else None
if hero and not hero.startswith("http"):
hero = _DUPONT_BASE + hero
# Fetch detail page for full data
detail_data = _dupont_detail(detail_url)
# Use postcode from detail if available
postcode = detail_data.get("postcode")
listings.append(RawListing(
url=detail_url,
source_makelaar="dupont",
adres=adres,
postcode=postcode,
stad=stad or _infer_stad(postcode),
prijs=prijs,
status=status,
hero_image_url=hero,
woningtype=detail_data.get("woningtype"),
bouwjaar=int(detail_data["bouwjaar"]) if detail_data.get("bouwjaar") else None,
woonoppervlak=parse_m2(detail_data.get("woonoppervlak")),
kamers=int(detail_data["kamers"]) if detail_data.get("kamers") else None,
slaapkamers=int(detail_data["slaapkamers"]) if detail_data.get("slaapkamers") else None,
energielabel=detail_data.get("energielabel"),
))
except Exception as e:
log.warning("dupont: parse fout: %s", e)
if len(cards) < 10:
break
page += 1
log.info("dupont: %d listings opgehaald", len(listings))
return listings
# ---------------------------------------------------------------------------
# SCRAPERS — exporteer hier alle actieve SSR adapters
# ---------------------------------------------------------------------------
@@ -745,4 +867,5 @@ SCRAPERS = {
'wassenaar': fetch_wassenaar,
'dens': fetch_dens,
'3dmakelaars': fetch_3dmakelaars,
'dupont': fetch_dupont,
}