SPB Git

spb/immo-ka Public

Immo-Ka — agrégateur des propriétés à vendre au Québec (73 connecteurs, ~40 000 annonces, React+FastAPI)

Python 67.2% TypeScript 19.4% CSS 12.9% HTML 0.5%
2.0 KB · 52 lines python
Raw Blame History
1# -----------------------------------------------------------------------------2# Immo-Ka — Agrégateur de maisons à vendre (province de Québec)3# Auteur : Simon-Pierre Boucher — contact@spboucher.ai4# connectors/jsonld.py : utilitaires partagés d'extraction schema.org (JSON-LD)5#   Beaucoup de sites d'agences (Sutton, et d'autres CMS immobiliers) publient6#   la liste des propriétés en JSON-LD `ItemList` — données propres et stables.7# -----------------------------------------------------------------------------8from __future__ import annotations910import json11import re1213_LD_RE = re.compile(r'<script[^>]+type="application/ld\+json"[^>]*>(.*?)</script>',14                    re.S | re.I)151617def iter_ld(html: str):18    """Itère les objets JSON-LD d'une page (chaque bloc, aplati depuis @graph)."""19    for block in _LD_RE.findall(html):20        block = block.strip()21        if not block:22            continue23        try:24            data = json.loads(block)25        except ValueError:26            continue27        nodes = data.get("@graph", [data]) if isinstance(data, dict) else data28        for node in (nodes if isinstance(nodes, list) else [nodes]):29            if isinstance(node, dict):30                yield node313233def item_list_elements(html: str) -> list[dict]:34    """Retourne les `itemListElement` (schema.org ItemList) trouvés dans la page."""35    out: list[dict] = []36    for node in iter_ld(html):37        elems = node.get("itemListElement")38        if isinstance(elems, list):39            out.extend(e for e in elems if isinstance(e, dict))40        # certaines pages imbriquent l'ItemList sous mainEntity41        me = node.get("mainEntity")42        if isinstance(me, dict) and isinstance(me.get("itemListElement"), list):43            out.extend(e for e in me["itemListElement"] if isinstance(e, dict))44    return out454647def sqm_to_sqft(value) -> float | None:48    try:49        return round(float(value) * 10.7639)50    except (TypeError, ValueError):51        return None52