HA webhook works, also more makelaars
This commit is contained in:
@@ -31,7 +31,7 @@
|
||||
| [x] | De Witte Garantiemakelaars | dewittegarantiemakelaars.nl | Philippusweg 2 |
|
||||
| [x] | Makelaardij Wassenaar | makelaardijwassenaar.nl | Gerrit Verboonstraat 12 |
|
||||
| [x] | 3D Makelaars | 3dmakelaars.nl | Gerrit Verboonstraat 17 |
|
||||
| [ ] | Dupont Makelaars | dupont.nl | Rotterdamsedijk 437 |
|
||||
| [x] | Dupont Makelaars | dupont.nl | Rotterdamsedijk 437 |
|
||||
| [x] | D&S Makelaardij | densmakelaars.nl | Land van Belofte 50 |
|
||||
| [ ] | Moerman & De Jong Makelaars | moerman-dejong.nl | Lange Kerkstraat 80B |
|
||||
| [ ] | Hagestein Makelaardij | — | Degerfors 54 |
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
|
||||
@@ -10,13 +10,13 @@ from adapters import SCRAPERS
|
||||
|
||||
logging.basicConfig(
|
||||
stream=sys.stdout,
|
||||
level=logging.DEBUG,
|
||||
level=logging.INFO, # debug costs too many tokens
|
||||
format="%(asctime)s %(levelname)s %(name)s — %(message)s",
|
||||
datefmt="%Y-%m-%dT%H:%M:%S",
|
||||
)
|
||||
|
||||
# --- change this to test a different adapter ---
|
||||
ADAPTER = SCRAPERS['3dmakelaars']
|
||||
ADAPTER = SCRAPERS['dupont']
|
||||
|
||||
if __name__ == "__main__":
|
||||
print(f"Testing adapter: {ADAPTER.__name__}")
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
import sys
|
||||
sys.path.insert(0, "../src")
|
||||
|
||||
import logging
|
||||
|
||||
from huizenbot import notify_ha, RawListing
|
||||
|
||||
|
||||
logging.basicConfig(
|
||||
stream=sys.stdout,
|
||||
level=logging.INFO, # debug costs too many tokens
|
||||
format="%(asctime)s %(levelname)s %(name)s — %(message)s",
|
||||
datefmt="%Y-%m-%dT%H:%M:%S",
|
||||
)
|
||||
|
||||
|
||||
TEST_LISTING = RawListing(
|
||||
url="https://home.kalsbeek.dev/api/webhook/new_house",
|
||||
source_makelaar="test",
|
||||
adres="Teststraat 1",
|
||||
stad="Delft",
|
||||
postcode="2613AA",
|
||||
prijs=350000,
|
||||
hero_image_url=None,
|
||||
)
|
||||
|
||||
TEST_TRAVEL = {
|
||||
"fiets_persoon1": 20,
|
||||
"fiets_persoon2": 35,
|
||||
"ov_persoon1": 30,
|
||||
"ov_persoon2": 45,
|
||||
}
|
||||
|
||||
if __name__ == "__main__":
|
||||
print("=== Home Assistant webhook ===")
|
||||
notify_ha(TEST_LISTING, TEST_TRAVEL)
|
||||
print(" verstuurd (check HA voor bevestiging)")
|
||||
|
||||
Reference in New Issue
Block a user