# centurion — Centurion / CP Living (cpliving.com) - site: https://www.cpliving.com/apartments-for-rent/quebec-city (Quartier QB, 2551 ch. des Quatre-Bourgeois, Sainte-Foy — 684 unités) - méthode: json-api — flux Rentsync/Lift `https://api.theliftsystem.com/v2/search?client_ids=21&city_ids=2310` (paramètres et auth_token lus dynamiquement sur la page + scripts/main.js, replis constants) ; galerie photo de la fiche propriété derrière le cache BD self.detail() - annonces: 1 (une par propriété de la région de Québec ; uid = id Lift `79867`, stable) - couverture (sur 1 annonce): adresse 100% (rue + ville + code postal), GPS 100%, description 100%, commodités 100%, photos 100% (6, pleine résolution), contact 100% ; prix/type/superficie/date : indisponibles tant que « No Vacancy » (voir plus bas) - fixture: ok (4 requêtes) · test: ok (2 verts) ## Découverte technique (anti-bot / Cloudflare) - La page de recherche référence un proxy legacy `widgets/search/api_proxy.php?client_id=21&city_id=2310` (attribut `data-ms-bcp` du div `.search-data`) — il renvoie **404** aujourd'hui : c'est un vestige. Le JS réel (`/scripts/main.js`) appelle `https://api.theliftsystem.com/v2/search` avec un `auth_token` embarqué en clair (`sswpREkUtyeYjeoahA2i` pour le client 21 en production). - Cloudflare accepte le UA de base.py sur cpliving.com ET sur api.theliftsystem.com : **aucun rendu JavaScript nécessaire** (plan (a) du protocole — l'endpoint direct suffit, ni session préalable ni Firecrawl). - Subtilité du flux : `city_ids` (pluriel) + `show_all_properties=true` sont requis ; la requête « complète » du site (min_rate=0&max_rate=10000…) renvoie une liste vide quand la propriété n'a aucune unité disponible (rates null filtrés côté API). ## Champs extraits - Flux Lift : id, permalink, name, address{address, city, province_code, postal_code, neighbourhood}, geocode{latitude, longitude}, availability_status_label (« No Vacancy »), min_availability_date, statistics.suites{rates.min/max, bedrooms, bathrooms, square_feet} (remplis seulement quand il y a vacance → prix « À partir de X $ », type d'unité si gamme sans ambiguïté, superficie min), details.overview (description HTML → texte), promotion, custom_fields.amenities (CSV : « In-suite laundry, Dishwasher, Microwave, Air conditioner, Balcony »), contact.phone → details.contact, pet_friendly (true → pets=« oui » ; false ignoré : ne distingue pas « interdit » de « non renseigné ») - Fiche propriété (HTML rendu serveur) : galerie assets.rentsync.com, réécrite en `/gallery/full/` (vérifié 200), via self.detail() (clé = hash de availability_count/status/rates/min_availability_date/photo → revisitée seulement quand le flux bouge) ## Champs indisponibles à la source - Prix, type d'unité, superficie, date de disponibilité : le Quartier QB est à « No Vacancy » (availability_count=0, statistics.suites tout à null) — l'annonce documente l'immeuble et se remplira automatiquement dès qu'une unité se libère - Détail par unité/suite : le site n'expose que `/v2/search` (aucun endpoint suites) ; le sommaire `statistics.suites` est le maximum disponible - Secteur : `neighbourhood` vide au flux (Sainte-Foy n'apparaît que dans la description) ; meublé, étage ## Fragilités - auth_token embarqué dans main.js : extrait dynamiquement (motif `client_id=21",e="&auth_token=…"`), repli constant — un changement de minification casserait l'extraction (couvert par le repli + la fixture) - REIT national (104 propriétés au flux sans filtre) : le garde-fou _QC_CITIES doit être maintenu si Centurion acquiert dans d'autres villes de la région - Libellés du flux en anglais (« No Vacancy ») — stockés bruts - Le format de `min_availability_date` (vide aujourd'hui) est supposé ISO ; seul un préfixe AAAA-MM-JJ strict est promu en availability_date ## Améliorations - 2026-08-08 — Expansion provinciale (lot 0) : `city_ids=2310,1039` (Québec + Gatineau, id vérifié au recensement Outaouais) ; garde-fou province_code=QC conservé et `_QC_CITIES` étendu (gatineau/hull/aylmer). Le flux Gatineau accole la province au nom de ville (« Gatineau QC ») → suffixe retiré (`_city_key` + affichage). Correctif au passage : `square_feet.min="0.0"` publié par le flux Gatineau produisait `area_sqft=0.0` (invalide) — garde de plausibilité 80–20 000 pi². +3 annonces à Gatineau : Nox (1 499 $), Nox 3 (1 525 $), Appartements Central (1 499 $), toutes « Available Now ». 1 → 4 annonces. Fixture réenregistrée (7 requêtes), 2 tests verts.