Comparateurs de prix
Contactez-moi- Angular 22 SSR
- CodeIgniter 4
- Elasticsearch
- Python
- Vespa
- MySQL
- Redis
- Affiliation
Le réseau en bref
Ce multisite est un réseau de comparateurs de prix thématiques. Chaque site couvre un seul univers produit et regroupe les offres de dizaines de marchands en ligne. Le visiteur trouve le bon produit au meilleur prix sans faire le tour des boutiques ; le site est rémunéré à l’affiliation quand il redirige vers le marchand.
Les sites du réseau :
| Univers | Site | Logo |
|---|---|---|
| Chaussures | meschaussures.fr | |
| Sneakers | messneakers.fr | |
| Vêtements | mesfringues.fr | |
| Bijoux | touslesbijoux.fr | |
| Montres | unemontre.fr | |
| Sacs | messacs.fr | |
| Bagages | votrebagage.com | |
| Lunettes | meslunettesenligne.fr | |
| Mobilier | lemobilier.fr | |
| Luminaires | monluminaire.com | |
| Linge de maison | monlinge.fr | |
| Arts de la table | monartdelatable.com | |
| Ustensiles de cuisine | mesustensiles.com | |
| Jouets | desjouetsparmilliers.com | |
| Drones | jeveuxundrone.com | |
| Animalerie | lesanimaleries.com | |
| Instruments de musique | mesinstruments.com |
Fonctionnalités communes :
- Catalogue multi-marchands : produits issus des flux des régies d’affiliation (AWin, Kwanko, NetAffiliation) et de l’API Amazon.
- Navigation à facettes : catégorie, type, marque, couleur, matière, taille, fourchette de prix, promotions et nouveautés, avec plusieurs tris.
- Recherche libre et pages de listes générées à partir de n’importe quelle combinaison de filtres.
- Fiche produit : prix actuel et ancien prix, remise, frais de port, images, lien vers le marchand.
- Annuaire des marques et guides d’achat.
- Liste d’envies et compte utilisateur (activation par email, réinitialisation du mot de passe).
But du projet
Construire un seul socle technique pour N sites de niche. Un site spécialisé se positionne mieux sur des requêtes précises (« bottines cuir femme marron », « suspension laiton salon ») qu’un généraliste. Pour que ce modèle tienne, le coût d’un site supplémentaire doit être quasi nul : même front, même back-office, même chaîne d’ingestion. Seules la configuration et les données changent.
Trois enjeux structurent le projet :
- La qualité des données : des millions de lignes hétérogènes venues des marchands, à classer et à normaliser automatiquement.
- Le référencement à grande échelle : des pages utiles, rapides et bien reliées entre elles sur chaque combinaison pertinente de filtres.
- La fraîcheur : des prix et des disponibilités à jour sans réindexer tout le catalogue à chaque passage.
Stack technique
- Front multisite : Angular 22, avec composants autonomes, Signals et détection de changement sans zone.js. Le rendu se fait côté serveur (Angular SSR sur Express) pour que chaque page arrive complète aux robots. Une seule application sert tous les domaines et charge la configuration du site à partir du nom d’hôte. Tests Jasmine/Karma et Playwright, CI GitLab avec analyse de sécurité Trivy.
- Back-office et API : CodeIgniter 4 (PHP 8), MySQL et cache Redis :
- API versionnées consommées par le front et l’application mobile, documentées en OpenAPI/Swagger ;
- administration des flux, des marques, des mises en avant, des textes SEO et des statistiques ;
- traçage OpenTelemetry ;
- une configuration par site : index, catégories et affichage.
- Chaîne d’ingestion : Python, avec un extracteur à base de règles (taxonomie, Aho-Corasick, RapidFuzz) et un traitement en flux multiprocessus.
- Moteur de recherche : Elasticsearch 9, avec Vespa en moteur alternatif alimenté en parallèle.
Mise à jour des flux
Les catalogues marchands arrivent sous forme de fichiers (CSV, XML, souvent compressés) aux formats tous différents. Un orchestrateur planifié parcourt chaque flux actif déclaré dans le back-office et lui applique la même chaîne :
- Téléchargement du flux, avec une nouvelle tentative en cas d’échec et un contrôle de taille minimale. La décompression se base sur le contenu réel du fichier (gzip, bzip2, zip) et non sur l’extension annoncée.
- Conversion en CSV UTF-8, en streaming : les gros fichiers XML ne sont jamais chargés entièrement en mémoire.
- Diff incrémental : chaque produit reçoit une empreinte qui est comparée à l’archive du passage précédent. Seuls les produits ajoutés ou modifiés sont retraités, et les produits disparus sont désactivés. Un flux strictement identique est ignoré.
- Extraction des attributs par un moteur de règles maison, sans modèle d’IA, pour un résultat déterministe et explicable :
- environ 15 000 règles déterminent la famille, le type, le sous-type et une soixantaine d’attributs (couleur, matière, genre, taille…) à partir du titre, de la description et de la catégorie fournie par le marchand ;
- l’automate Aho-Corasick sert aux correspondances exactes, RapidFuzz à la correspondance approximative ;
- le traitement est réparti sur tous les cœurs.
- Construction de l’offre : prix actuel et ancien prix, pourcentage de remise, frais de port, images, lien affilié, EAN, marque.
- Envoi en masse (
_bulkNDJSON) vers Elasticsearch et Vespa. - Cycle de vie en fin de passage :
- activation des promotions et des nouveautés du jour, puis retrait des nouveautés trop anciennes ;
- retrait des remises devenues trop faibles et désactivation des prix aberrants ;
- compactage de l’index.
- Rapport : chaque flux reçoit son bilan (ajouts, modifications, retraits, erreurs) dans le back-office, et un email récapitulatif part en fin de passage. L’échec d’un flux n’interrompt jamais le traitement des suivants.
La base Elasticsearch
Elasticsearch est le cœur du catalogue. Il sert à la fois de stockage des produits et de moteur de recherche des 17 sites :
- Un index produits commun à tout le réseau. Chaque site n’en lit que sa part grâce à sa configuration (famille, catégories). Les lectures et les écritures passent par deux points d’accès distincts : l’ingestion peut écrire pendant que les sites lisent.
- Un schéma structuré par préfixes :
input_*pour les données brutes normalisées,out_*pour les attributs déduits,keyword_*pour les champs de filtrage exact,prix_*pour les montants. Des modèles dynamiques typent automatiquement chaque nouveau champ. - Des écritures non destructives : chaque produit est mis à jour par update/upsert, jamais réécrit en entier. Un flux partiel n’efface donc pas les données des autres flux. L’identifiant
flux_produitrend chaque ligne unique. - La recherche à facettes : les agrégations calculent à la volée les compteurs de chaque filtre (marques, couleurs, tranches de prix…) affichés à côté des résultats.
- Des drapeaux métier : promotion, nouveauté et désactivation manuelle sont posés par l’ingestion ou par le back-office. Les sites filtrent dessus sans recalcul.
L’enrichissement des marques
Les marchands écrivent la même marque de dix façons différentes : « NIKE », « Nike Inc. », « nike sportswear »… Sans normalisation, la facette « marque » serait inutilisable et les pages marque se cannibaliseraient. L’enrichissement s’appuie sur les mécanismes natifs d’Elasticsearch :
- Un index de référence
marquesassocie chaque graphie brute (normalisée sans accents ni casse) à la marque canonique. - Une politique d’enrichissement (
enrich policy) est compilée à partir de cet index, et un pipeline d’ingestionmarque_lookupl’applique automatiquement à chaque produit écrit. La marque normalisée (out_marque) est calculée par Elasticsearch lui-même, sans code applicatif dans la boucle. - La boucle de validation dans le back-office : pour chaque flux, un écran liste les marques rencontrées mais pas encore référencées. L’opérateur les rattache à une marque existante ou en crée une nouvelle, puis « recharge » : la politique est recompilée et les produits concernés sont ré-enrichis en tâche de fond.
- Pour Vespa, qui n’a pas d’enrichissement à l’ingestion, la chaîne Python embarque un export statique de la table des marques et calcule
out_marqueavant l’envoi. Les deux moteurs restent ainsi cohérents.
Référencement
- Une URL pour chaque intention de recherche : la route générique du front transforme n’importe quel chemin (
/bottines,/bottines/cuir,/bottines/cuir/marron…) en page de liste filtrée. Chaque page a son title, sa meta description, son H1 et son texte d’introduction, gérés URL par URL dans le back-office. - Rendu serveur : le HTML complet (produits, textes, liens) est servi aux robots, avec le bon code HTTP (404 réelle pour une page vide) au lieu d’une coquille JavaScript.
- Une URL canonique sur chaque page, et des meta robots pilotées page par page, pour ne pas indexer les combinaisons sans valeur.
- Des sitemaps XML par site, dont un sitemap d’images pour Google Images, très utile dans des univers visuels comme la mode, les bijoux ou la décoration.
- La performance : cache Redis côté API, rendu serveur, chargement différé des pages Angular.
Maillage interne
- Des blocs de liens connexes par URL : une table de maillage associe à chaque page de liste une sélection de pages proches (de « armoire » vers « confiturier »…). L’API la renvoie avec les textes SEO, et le front l’affiche sous forme de liens en dur.
- Le fil d’Ariane sur les listes et les fiches produit : chaque niveau de filtre renvoie vers son parent, ce qui fait remonter l’autorité vers les pages de liste stratégiques.
- L’annuaire des marques : seules les marques marquées « à indexer » sont de vrais liens
<a href>explorables. Les autres restent navigables pour l’utilisateur sans diluer le budget de crawl.
Données structurées
L’API du back-office génère les blocs JSON-LD Schema.org à partir des mêmes données que la page. Le front les injecte dans le HTML rendu côté serveur :
WebSite+SearchAction: déclare le moteur de recherche interne de chaque site.WebPagesur les pages de liste.BreadcrumbList, construit à partir des filtres actifs : le chemin hiérarchique peut s’afficher dans les résultats Google.Productsur les fiches produit : nom, image, description, marque (Brand, issue de la marque normalisée) et une offre (Offer) avec prix, devise, disponibilité et vendeur (le marchand).
Les blocs sont échappés côté front : un titre produit venu d’un flux marchand ne peut pas fermer la balise <script> et casser la page.
Historique
Les comparateurs de prix apparaissent avec le e-commerce à la fin des années 1990 (Kelkoo, LeGuide). Ils reposent sur un modèle de coût par clic ou d’affiliation reversé par les marchands. La montée de Google Shopping a poussé le marché vers des comparateurs spécialisés, plus pertinents sur des requêtes précises : c’est le positionnement de ce réseau.
Mon expertise
Depuis 2015, je conçois et j’édite des comparateurs de prix sur des niches (mode, décoration, high-tech), avec un pilotage complet : définition des besoins, création des sites, des API et des applications mobiles, et optimisation SEO continue.
Le réseau actuel de 17 sites repose sur un seul socle technique (front Angular SSR, back-office CodeIgniter, ingestion Python vers Elasticsearch). Pendant dix ans, plus de 800 flux Talend intégraient les marchands, avant la bascule vers une solution Python pilotée par des règles.
Réalisations
- meschaussures.fr : comparateur de chaussures.
- touslesbijoux.fr : comparateur de bijoux.
- lemobilier.fr : comparateur de mobilier.
- Les 14 autres sites du réseau sont listés en haut de page.