Auto·Ka
Toutes les voitures usagées à vendre au Québec. Un seul endroit.
Agrégateur indépendant de voitures usagées — chaque annonce avec ses photos, ses caractéristiques standardisées (année, km, transmission, carburant, VIN…) et un lien direct vers l'annonce originale du concessionnaire. Toujours à jour, automatiquement. Suivi des baisses de prix intégré.
Pourquoi Auto-Ka ?
Chercher une auto usagée au Québec, c'est ouvrir des dizaines de sites de concessionnaires — chacun avec sa navigation, ses filtres, son format. Auto-Ka retourne le problème : un connecteur dédié par commerce visite chaque site à la source (aucune plateforme d'annonces revendue), normalise chaque véhicule vers un schéma unique et détecte les changements en continu.
Les sites de concessionnaires n'offrent pas de webhooks. Auto-Ka reproduit l'équivalent : synchronisation périodique + hash de contenu → arrivages, baisses de prix et ventes détectés automatiquement. Un véhicule qui disparaît du site source est marqué vendu dans Auto-Ka.
Les chiffres
| Métrique | Valeur |
|---|---|
| Véhicules en vente | 13 713 |
| Concessionnaires connectés | 99 (95+ connecteurs actifs) |
| Régions administratives couvertes | 18 / 17 (+ Outaouais frontalier) |
| Annonces avec prix affiché | 100 % (jamais de prix inventé) |
| Annonces avec kilométrage | 99,9 % |
| Annonces avec photos | ~99 % |
| Prix moyen du marché | 28 181 $ |
| Cycle de rafraîchissement | 2 h (PM2 watcher) |
L'architecture en 30 secondes
flowchart LR
subgraph Sources["99 concessionnaires"]
S1["D2C Media ×50 · SM360 ×8<br/>AMVOQ ×6 · EvalAuto ×11<br/>Convertus ×4 · customs<br/>HGrégoire · AED · Beaucage…"]
end
subgraph AutoKa["Auto-Ka"]
C["Connecteurs<br/><i>1 adaptateur / plateforme</i>"] --> N["Normalisation<br/><i>schéma Vehicle unique</i>"]
N --> D[("SQLite<br/>hash + diff + prix")]
D --> A["API FastAPI<br/>/api/vehicles · /api/facets"]
A --> F["React 18 + Vite<br/>filtres auto · fiches · stats"]
end
W["⏱ Watcher 2 h<br/>(PM2)"] -.-> C
S1 --> C
F --> U["🔑 Acheteur"]
| Couche | Rôle | Fichiers |
|---|---|---|
| Connecteurs | 1 module par plateforme de site (D2C Media, SM360, AMVOQ Focus 360, EvalAuto Gatsby/Next.js, Convertus VMS, ADWS, EDealer…) avec 1 sous-classe par concessionnaire ; JSON-LD schema.org, API JSON internes, sitemaps ; Firecrawl pour les sites derrière Cloudflare | autoka/connectors/*.py |
| Schéma | Vehicle standardisé : marque, modèle, année, prix, km, transmission, carburant, motricité, carrosserie, couleurs, VIN, photos, région |
autoka/schema.py |
| Normalisation | Prix/km/année depuis le texte, marques canoniques, ville → région administrative, inférence motricité/carburant depuis les badges du titre (AWD, PHEV…) | autoka/normalize.py |
| Diff engine | Upsert par hash de contenu — nouveau / modifié / vendu (délai de grâce 2 syncs), historique de prix, détection de dérive | autoka/db.py |
| API | Filtres marque / modèle / année / prix / km / carburant / motricité / région / concessionnaire, facettes, stats marché, baisses de prix récentes | autoka/web.py |
| Frontend | Design « éditorial sharp », accent orange racing : filtres auto complets, fiches avec galerie photos, historique de prix et véhicules similaires | frontend/ |
Le marché en direct
Démarrage rapide
git clone https://git.spboucher.ai/auto-ka.git && cd auto-ka
# Backend
python3 -m venv .venv && .venv/bin/pip install -r requirements.txt
# Frontend
cd frontend && npm install && npm run build && cd ..
# Sites derrière Cloudflare (optionnel)
echo "FIRECRAWL_API_KEY=fc-votre-cle" > .env
# Ingestion puis service
.venv/bin/python run.py sync # toutes les sources (ou: run.py sync forceoccasion)
.venv/bin/python run.py serve 8080 # → http://localhost:8080
.venv/bin/python run.py watch 120 # resynchronisation en boucle (minutes)Ajouter un concessionnaire (≈ 6 lignes)
L'enregistrement est auto-découvrant : déposez un module dans
autoka/connectors/ contenant une sous-classe de BaseConnector avec un
source_id — c'est tout. Pour un site D2C Media (le fournisseur le plus
répandu au Québec) :
# dans autoka/connectors/d2c_dealers.py
class MonConcessionnaire(D2CConnector):
source_id = "monconcessionnaire"
base_url = "https://www.monconcessionnaire.ca"
dealer_name = "Mon Concessionnaire"
city = "Sherbrooke"Puis : .venv/bin/python run.py sync monconcessionnaire — et l'inventaire
apparaît sur le site avec fiches, galeries et liens sources. Ajoutez l'entrée
correspondante dans data/sources.json pour la page Sources.
API
| Endpoint | Description |
|---|---|
GET /api/vehicles?make=&model=®ion=&price_max=&km_max=&fuel=&sort= |
Recherche filtrée et triée |
GET /api/vehicles/{uid} |
Fiche complète (photos, historique de prix, similaires) |
GET /api/facets?make= |
Valeurs distinctes pour construire les filtres |
GET /api/sources |
Registre des concessionnaires + compteurs + dernière sync |
GET /api/stats |
Totaux, moyennes, top marques/régions, baisses de prix récentes |
POST /api/sync |
Déclenche une synchronisation en arrière-plan |
Couverture
Grands réseaux — HGrégoire (mégacentres partout au Québec), Automobile En Direct, Occasion Beaucage (7 concessions), Le Prix du Gros, Méga Centre de liquidation, St-Jérôme Auto Dépôt, Ste-Foy Chrysler, Desmeules, Entrepôt Auto Durocher…
Toutes les régions — Montérégie, Capitale-Nationale, Laurentides, Mauricie, Laval, Estrie, Outaouais, Centre-du-Québec, Chaudière-Appalaches, Lanaudière, Montréal, Saguenay–Lac-Saint-Jean, Bas-Saint-Laurent, Abitibi-Témiscamingue, Côte-Nord, Gaspésie…
Chaque source non connectable est documentée avec sa raison dans
data/sources.json (ex. : doublon d'inventaire d'un autre site du même
groupe, vérifié par VIN).
Production
Déployé sous PM2 (3 processus) derrière ngrok :
auto-ka-web .venv/bin/python run.py serve 8095 # API + frontend
auto-ka-sync .venv/bin/python run.py watch 120 # resync 2 h
auto-ka-ngrok ngrok http --url=www.auto-ka.com 8095 # tunnelPhilosophie d'exploitation : on ne pousse que le code — le serveur maintient ses données lui-même.
Principes
- À la source — les annonces viennent des sites des concessionnaires eux-mêmes, jamais des plateformes d'agrégation existantes.
- Politesse — délai ≥ 1 s entre requêtes, cache des pages détail (revalidation hebdomadaire), backoff sur rate-limit, User-Agent identifié.
- Fidélité — aucun prix inventé : si la source n'affiche pas de prix,
price = null(« Prix sur demande »). - Traçabilité — chaque fiche renvoie vers l'annonce originale.
- Robustesse — un connecteur qui casse n'affecte jamais les autres ; un 404 (véhicule vendu) ne bloque jamais une source ; détection de dérive (chute de volume → retraits suspendus + alerte).