SPB Git forge

spb/lou-ka

Public

Lou·Ka — tous les logements à louer du Québec, un seul endroit.

232commits 1branches 0releases
172.9 MBsize
maindefault branch
2 days agolast push
HTML 98.9% Python 0.6%
3.7 KB · 91 lines python
Raw Blame History
1# -----------------------------------------------------------------------------2# Lou-Ka — Agrégateur de logements à louer (province de Québec)3# Auteur : Simon-Pierre Boucher — contact@spboucher.ai4# connectors/primo.py : connecteur Primo Immobilier (primoimmobilier.ca —5#   condos locatifs de luxe en Montérégie : Lumicité Condominiums à6#   Saint-Mathieu-de-Beloeil et Quartier Trinité à Saint-Basile-le-Grand).7#   WordPress rendu serveur mais SANS inventaire d'unités : chaque page8#   projet affiche un seul prix plancher « À partir de 2075$/mois » (les9#   typologies 3½/4½/5½ n'apparaissent que dans le formulaire, sans prix).10#   Granularité = PROJET (une annonce par projet, prix « à partir de »).11#   external_id = slug de la page projet — stable.12# -----------------------------------------------------------------------------13from __future__ import annotations1415import html as _html16import re1718from ..schema import Listing19from .base import BaseConnector2021BASE = "https://primoimmobilier.ca"2223# (slug page, nom du projet, ville)24PROJECTS: tuple[tuple[str, str, str], ...] = (25    ("saint-mathieu-de-beloeil", "Lumicité Condominiums",26     "Saint-Mathieu-de-Beloeil"),27    ("saint-basile-le-grand", "Quartier Trinité", "Saint-Basile-le-Grand"),28)2930H1_RE = re.compile(r"<h1[^>]*>([\s\S]*?)</h1>", re.I)31FROM_RE = re.compile(r"À\s+partir\s+de\s+([\d\s  ]{3,9})\$\s*/\s*mois", re.I)32SCRIPT_RE = re.compile(r"<(script|style)[\s\S]*?</\1>", re.I)33TAG_RE = re.compile(r"<[^>]+>")34IMG_RE = re.compile(35    r'https://primoimmobilier\.ca/wp-content/[^"\s)]+\.(?:jpe?g|png|webp)',36    re.I)373839class PrimoConnector(BaseConnector):40    source_id = "primo"41    request_delay = 0.84243    def fetch(self) -> list[Listing]:44        listings: list[Listing] = []45        for slug, name, city in PROJECTS:46            url = f"{BASE}/{slug}/"47            try:48                html = self.get(url).text49            except Exception:50                continue51            flat = re.sub(r"[\s  ]+", " ",52                          TAG_RE.sub(" ", _html.unescape(53                              SCRIPT_RE.sub(" ", html))))54            pm = FROM_RE.search(flat)55            price = None56            if pm:57                try:58                    price = float(re.sub(r"[\s  ]", "", pm.group(1)))59                except ValueError:60                    price = None61            if price is None or not (500 <= price <= 8000):62                continue                     # pas de prix publié = pas d'annonce6364            hm = H1_RE.search(html)65            title = (re.sub(r"\s+", " ", _html.unescape(66                         TAG_RE.sub(" ", hm.group(1)))).strip()67                     if hm else f"Condos locatifs {name}")6869            images = [u for u in dict.fromkeys(IMG_RE.findall(html))70                      if not re.search(r"logo|icon|favicon|banners", u, re.I)71                      ][:10]7273            listings.append(Listing(74                source=self.source_id,75                external_id=slug,76                url=url,77                title=title,78                address="",                  # adresse civique non publiée79                city=city,80                price=price,81                price_label=f"à partir de {int(price)} $/mois",82                description=f"{name} à {city} — condos locatifs de luxe de "83                            "Primo Immobilier (typologies 3½ à 5½). "84                            "Ascenseur, stationnement et rangement "85                            "intérieurs, plafonds de 9 pieds, comptoirs de "86                            "quartz, accessible aux personnes à mobilité "87                            "réduite.",88                images=images,89            ))90        return listings91