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%
4.1 KB · 109 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/inovario.py : connecteur Inovario (inovario.com)5#   Promoteur-gestionnaire de Châteauguay — deux projets locatifs : rue6#   St-Denis et Quartier du Centre Signature. WordPress/Elementor rendu7#   serveur : le sitemap Yoast (/sitemap_index.xml → page-sitemap.xml) liste8#   une page par modèle d'appartement (chateauguay-<projet>-<type>[-modele-…]).9#   Pas de prix ni d'unités individuelles publiés. Granularité : modèle10#   (typologie).11# -----------------------------------------------------------------------------12from __future__ import annotations1314import re1516from bs4 import BeautifulSoup1718from .base import BaseConnector19from ..schema import Listing, normalize_unit_type2021BASE = "https://inovario.com"22SITEMAP = f"{BASE}/page-sitemap.xml"2324CITY = "Châteauguay"2526LOC_RE = re.compile(r"<loc>([^<]+)</loc>")27MODEL_RE = re.compile(r"^https://inovario\.com/(chateauguay-[a-z0-9-]+)/?$")28TYPE_RE = re.compile(r"(\d)-(?:1-2|et-demi)")29SQFT_RE = re.compile(r"(\d{3,4})-pc")30IMG_RE = re.compile(r'https://inovario\.com/wp-content/uploads/'31                    r'[^"\s\\)]+\.(?:jpe?g|png|webp)', re.I)323334class InovarioConnector(BaseConnector):35    source_id = "inovario"36    request_delay = 0.63738    def fetch(self) -> list[Listing]:39        listings: list[Listing] = []40        try:41            xml = self.get(SITEMAP).text42        except Exception:43            return listings4445        for url in LOC_RE.findall(xml):46            m = MODEL_RE.match(url.strip())47            if not m:48                continue49            slug = m.group(1)50            mt = TYPE_RE.search(slug)51            if not mt:52                continue          # pages de projet/hub, pas des modèles53            unit_type = normalize_unit_type(f"{mt.group(1)}½")5455            if "st-denis" in slug:56                project = "Rue St-Denis"57                address = "rue Saint-Denis, Châteauguay"58            else:59                project = "Quartier du Centre Signature"60                address = "rue Principale, Châteauguay"6162            sqft = None63            ms = SQFT_RE.search(slug)64            if ms:65                sqft = float(ms.group(1))6667            title, amenities, images = "", [], []68            try:69                html = self.get(url).text70                soup = BeautifulSoup(html, "html.parser")71                h1 = soup.find("h1")72                if h1:73                    title = h1.get_text(" ", strip=True)74                # « CARACTÉRISTIQUES DE NOS APPARTEMENTS » : liste à puces75                for li in soup.select("ul li"):76                    t = li.get_text(" ", strip=True)77                    if 3 < len(t) < 90 and not li.find("a"):78                        amenities.append(t)79                images = [u for u in dict.fromkeys(IMG_RE.findall(html))80                          if not re.search(r"logo|icon|favicon", u, re.I)][:15]81            except Exception:82                pass8384            variant = ""85            mv = re.search(r"(modele-[\w-]+|coin|centre|den)$", slug)86            if mv:87                variant = mv.group(1).replace("modele-", "modèle ")8889            listings.append(Listing(90                source=self.source_id,91                external_id=slug,92                url=url,93                title=title or f"{unit_type} — {project}, Châteauguay",94                address=address,95                city=CITY,96                unit_type=unit_type,97                area_sqft=sqft,98                availability="",99                details={"project": project,100                         **({"variant": variant} if variant else {})},101                description=f"Appartement {unit_type} de style condo du "102                            f"projet {project} à Châteauguay : planchers de "103                            f"béton insonorisés, aires ouvertes et grande "104                            f"fenestration. Prix sur demande.",105                amenities=list(dict.fromkeys(amenities))[:15],106                images=images,107            ))108        return listings109