47 KiB
Vérification Scraping Amazon - Analyse des erreurs
Date d'analyse: 2026-01-18
Résumé exécutif des bugs identifiés
Bugs récurrents (P1 - Priorité haute)
| # | Bug | Occurrences | Cause racine |
|---|---|---|---|
| 1 | MSRP incorrect | 5/8 produits | Sélecteur trop large capture prix de produits sponsorisés/recommandés |
| 1b | MSRP = prix bas 30j | 1/8 produits | select_one() prend le 1er prix barré (prix bas 30j) au lieu du 2ème (MSRP) |
| 2 | Stock "Inconnu" affiché | 3/8 produits | Parser ne reconnaît pas "expédié sous" + UI affiche "Inconnu" au lieu de masquer |
| 3 | "EVOL. 30 JOURS" affiché | Tous produits | Donnée calculée affichée alors qu'elle n'existe pas sur Amazon |
Bugs ponctuels (P2)
| # | Bug | Produit | Cause |
|---|---|---|---|
| 4 | Amazon Choice faux positif | Produit 3 | Détection sur élément vide |
| 5 | Type "Ecran" pour carte graphique | Produit 4 | Classification mots-clés incorrecte |
| 6 | Type "PC portable" pour RAM | Produit 6 | Classification mots-clés incorrecte |
Notes importantes
- Prix occasion : Ne pas tenir compte des prix occasion (ex: 245€ vs 223€ neuf sur produit 6)
- Différence HTTP/Playwright : Le HTML diffère selon la méthode de fetch, impactant l'extraction MSRP
Erreur Playwright détectée
Message d'erreur
Erreur: Erreur Playwright: BrowserType.launch: Executable doesn't exist at /root/.cache/ms-playwright/chromium_headless_shell-1200
Impact
Quand Playwright échoue, le système bascule sur HTTP. Le HTML retourné par HTTP diffère de celui de Playwright :
- HTTP : Contient plus de sections sponsorisées/recommandations avec des prix barrés
- Playwright : HTML plus "propre" après exécution JavaScript
Cela explique pourquoi certains MSRP incorrects sont capturés : le fallback HTTP expose des prix de produits tiers que Playwright aurait masqués ou chargés différemment.
Correction requise
# Installer les navigateurs Playwright
playwright install
Défauts globaux (tous produits)
❌ ERREUR UI: "EVOL. 30 JOURS" ne devrait pas être affiché
Problème: Le Web UI affiche "EVOL. 30 JOURS: +0.0%" (ou autre valeur) sur tous les produits, alors que cette donnée n'existe pas sur Amazon.
Règle : Seules les données scrapées depuis la source doivent être affichées dans le bloc produit. Une donnée absente de la source = ne pas afficher.
Distinction importante :
- ❌ "EVOL. 30 JOURS" → Donnée calculée, non présente sur Amazon → Ne pas afficher
- ✅ Graphique historique → Basé sur les scrapes passés de PriceWatch → Légitime
Correction requise : Supprimer la ligne "EVOL. 30 JOURS" du bloc d'informations produit.
Produit 6 : Corsair Vengeance SODIMM 32Go
URL: https://www.amazon.fr/dp/B08GSTF5NJ?th=1
Comparaison: Données Amazon vs Données Scrapées
| Champ | Valeur Amazon (source) | Valeur Scrapée (Web UI) | Statut |
|---|---|---|---|
| Titre | Corsair Vengeance SODIMM 32Go (2x16Go) DDR4 3200MHz C22... | Corsair Vengeance SODIMM 32Go (2x16Go) DDR4 3200MHz C22... | ✅ OK |
| Prix | 245,00€ (occasion) / 223,02€ (neuf) | 223,02 € | ⚠️ VOIR NOTE |
| Prix conseillé (MSRP) | Non affiché sur Amazon | 606,99 € | ❌ ERREUR |
| Stock | Non affiché explicitement | "Inconnu" | ⚠️ À NE PAS AFFICHER |
| Note | 4,7 (8 626) | 4,7 (8 626) | ✅ OK |
| Choix Amazon | Non visible sur capture | Oui | ⚠️ À VÉRIFIER |
| Référence (ASIN) | B08GSTF5NJ | B08GSTF5NJ | ✅ OK |
| Image principale | Image RAM Corsair | Image RAM Corsair | ✅ OK |
| Type | - | PC portable | ❌ ERREUR |
Défauts identifiés
1. ❌ ERREUR: MSRP incorrect (606,99 €) - Capture de prix tiers
Problème: Le Web UI affiche "PRIX CONSEILLÉ: 606,99€" alors qu'Amazon n'affiche aucun prix conseillé pour ce produit.
Cause racine identifiée : Le sélecteur MSRP capture un prix barré d'un produit tiers dans la section "CardInstance" (recommandations).
Source HTML (HTTP): #CardInstanceZ_u0EeRMlrOaTZL9bV_a9A
Prix capturé: €606,99 (produit recommandé, pas le produit principal)
Note : Le HTML diffère entre HTTP et Playwright. En HTTP, le prix 606,99€ est trouvé. En Playwright, le parser retourne None.
Lien avec erreur Playwright : L'erreur Executable doesn't exist at /root/.cache/ms-playwright/chromium_headless_shell-1200 force le fallback HTTP, qui capture ce prix incorrect depuis la section recommandations.
Même cause récurrente : Le sélecteur span.a-text-price span.a-offscreen n'est pas restreint au bloc prix principal.
2. ⚠️ NOTE: Prix neuf vs occasion
Observation : Amazon affiche en évidence le prix occasion (245,00€) alors que le prix neuf (223,02€) est moins visible.
Le parser capture correctement le prix neuf (223,02€), ce qui est le comportement souhaité.
Pas une erreur, mais une subtilité de mise en page Amazon à connaître.
3. ❌ ERREUR: Type "PC portable" incorrect
Problème : Le produit est de la RAM SODIMM (pour portables), pas un PC portable lui-même.
Cause : Le système de classification a probablement détecté "Ordinateur Portable" dans le titre et a mal catégorisé.
4. ⚠️ Stock "Inconnu" ne devrait pas être affiché
Comme établi précédemment, si Amazon n'affiche pas de stock → ne pas afficher "Inconnu".
Résumé produit 6
| Priorité | Problème | Récurrent ? |
|---|---|---|
| 🟠 P1 | MSRP incorrect (donnée historique corrompue) | ✅ Oui |
| 🟡 P2 | Type "PC portable" au lieu de "RAM" | 🆕 Erreur classification |
| 🟡 P2 | Stock "Inconnu" affiché inutilement | ✅ Oui |
Produit 5 : Samsung SSD 9100 Pro 2To
URL: https://www.amazon.fr/dp/B0DWFLPMM5?th=1
Comparaison: Données Amazon vs Données Scrapées
| Champ | Valeur Amazon (source) | Valeur Scrapée (Web UI) | Statut |
|---|---|---|---|
| Titre | Samsung SSD Interne 9100 Pro, NVMe 2.0 PCIe 5.0x4, Capacité 2To... | Samsung SSD Interne 9100 Pro, NVMe 2.0 PCIe 5.0x4, Capacité 2To... | ✅ OK |
| Prix | 249,99 € | 249,99 € | ✅ OK |
| Prix conseillé (MSRP) | 329,99 € | 329,99 € | ✅ OK |
| Réduction | -24 % | -24 % | ✅ OK |
| Stock | Non affiché explicitement (mais bouton "Ajouter au panier" présent) | "Inconnu" | ⚠️ AMÉLIORABLE |
| Note | 4,7 (966) | 4,7 (966) | ✅ OK |
| Choix Amazon | Non visible sur capture | Oui | ⚠️ À VÉRIFIER |
| Référence (ASIN) | B0DWFLPMM5 | B0DWFLPMM5 | ✅ OK |
| Image principale | Image SSD Samsung | Image SSD Samsung | ✅ OK |
| Catégorie | SSD | SSD | ✅ OK |
Défauts identifiés
1. ⚠️ AVERTISSEMENT: Stock "Inconnu" alors que produit disponible
Problème: Le stock est affiché comme "Inconnu" alors que le produit est clairement disponible (bouton "Ajouter au panier", livraison Prime).
Données HTML :
#availability: "" (vide)
#availability span: "" (vide)
Bouton "Ajouter au panier": Présent
Livraison Prime: Présent
Cause racine :
Amazon n'affiche pas toujours "En stock" explicitement. Pour certains produits, le #availability est vide mais le produit est disponible.
Amélioration proposée :
# Si #availability est vide mais bouton panier présent → IN_STOCK
if not text and soup.select_one('#add-to-cart-button'):
return StockStatus.IN_STOCK, "Disponible (panier)", True
2. ✅ MSRP correct
Ce produit confirme que le MSRP fonctionne quand il est réellement affiché sur la page (329,99€ barré visible sur Amazon).
Résumé produit 5
| Priorité | Problème | Récurrent ? |
|---|---|---|
| 🟡 P2 | Stock "Inconnu" malgré disponibilité (pattern #availability vide) | 🆕 Nouveau pattern |
Note positive : Prix, MSRP (-24%), note et catégorie sont tous corrects.
Produit 4 : MSI NVIDIA GeForce RTX 5060 Ti
URL: https://www.amazon.fr/dp/B0F32N1ZGH
Comparaison: Données Amazon vs Données Scrapées
| Champ | Valeur Amazon (source) | Valeur Scrapée (Web UI) | Statut |
|---|---|---|---|
| Titre | MSI NVIDIA GeForce RTX 5060 Ti 16G Inspire 2X OC Carte Graphique 16 Go GDDR7... | MSI NVIDIA GeForce RTX 5060 Ti 16G Inspire 2X OC Carte Graphique 16 Go GDDR... | ✅ OK |
| Prix | 509,00 € | 509 € | ✅ OK |
| Prix conseillé (MSRP) | Non affiché sur Amazon | 102,99 € | ❌ ERREUR |
| Stock | "En stock" | "En stock" | ✅ OK |
| Note | 4,6 (211) | 4,6 (211) | ✅ OK |
| Choix Amazon | Oui (badge visible) | Oui | ✅ OK |
| Référence (ASIN) | B0F32N1ZGH | B0F32N1ZGH | ✅ OK |
| Image principale | Image carte graphique MSI | Image carte graphique MSI | ✅ OK |
| Catégorie | Cartes graphiques | Informatique | ✅ OK |
| Type | - | Ecran | ❌ ERREUR |
Défauts identifiés
1. ❌ ERREUR: MSRP incorrect (102,99 €)
Problème: Le Web UI affiche "PRIX CONSEILLÉ: 102,99€" pour une carte graphique à 509€. C'est absurde (MSRP < prix actuel).
Cause racine identifiée : Le prix 102,99€ provient d'un produit sponsorisé affiché sur la page.
Source HTML: #sp_detail_B08ZCHF59L (produit sponsorisé)
Même problème récurrent : Le sélecteur MSRP capture des prix barrés de produits tiers (sponsorisés, similaires, etc.).
2. ❌ ERREUR: Type "Ecran" incorrect
Problème: Le produit est une carte graphique, pas un écran. La classification automatique est erronée.
Cause probable : Le système de classification par mots-clés a mal catégorisé le produit.
Résumé produit 4
| Priorité | Problème | Récurrent ? |
|---|---|---|
| 🟠 P1 | MSRP incorrect (102,99€ d'un produit sponsorisé) | ✅ Oui (3ème occurrence) |
| 🟡 P2 | Type "Ecran" au lieu de "Carte graphique" | 🆕 Erreur classification |
Produit 3 : ASUS TUF Gaming A16
URL: https://www.amazon.fr/dp/B0DQ8M74KL?th=1
Comparaison: Données Amazon vs Données Scrapées
| Champ | Valeur Amazon (source) | Valeur Scrapée (Web UI) | Statut |
|---|---|---|---|
| Titre | ASUS TUF Gaming A16-TUF608UH-RV054W 16 Pouces FHD Plus 165Hz... | ASUS TUF Gaming A16-TUF608UH-RV054W 16 Pouces FHD Plus 165Hz... | ✅ OK |
| Prix | 1 259,99 € | 1 259,99 € | ✅ OK |
| Prix conseillé (MSRP) | 1 699,99 € | 1 699,99 € | ✅ OK |
| Réduction | -26 % | -26 % | ✅ OK |
| Stock | "En stock" | "En stock" | ✅ OK |
| Note | 4,7 (7) | 4,7 (7) | ✅ OK |
| Choix Amazon | ❌ Non (c'est "Exclusivité Amazon") | Oui | ❌ ERREUR |
| Référence (ASIN) | B0DQ8M74KL | B0DQ8M74KL | ✅ OK |
| Image principale | Image laptop ASUS TUF | Image laptop ASUS TUF | ✅ OK |
| Catégorie | Ordinateurs portables classiques | Informatique | ✅ OK |
| Type | - | PC portable | ✅ OK |
Défauts identifiés
1. ❌ ERREUR: "Choix Amazon" faux positif
Problème: Le Web UI affiche "CHOIX AMAZON: Oui" alors qu'Amazon affiche "Exclusivité Amazon" (badge différent).
Données HTML :
#acBadge_feature_div: "" (vide)
Badge réel: "Exclusivité Amazon" (classe: ae-badge-rectangle-desktop)
Cause racine :
La méthode _extract_amazon_choice() détecte l'élément #acBadge_feature_div qui existe dans le DOM mais est vide. Le parser retourne True simplement parce que l'élément existe.
Fichier concerné: store.py:496-520 - méthode _extract_amazon_choice()
Correction proposée :
def _extract_amazon_choice(self, soup, debug):
for selector in selectors:
element = soup.select_one(selector)
if element:
text = element.get_text(strip=True)
# Ne retourner True que si le texte contient vraiment "Choix d'Amazon"
if not text:
continue # Élément vide = pas de badge
if "choix d'amazon" in text.lower() or "amazon's choice" in text.lower():
return True, text
return None, None
2. ℹ️ OBSERVATION: Badge "Exclusivité Amazon" non capturé
Opportunité : Ajouter un champ amazon_exclusive pour capturer ce badge distinct.
# Nouveau sélecteur
amazon_exclusive:
- "span.ae-badge-text-desktop"
- ".badge-wrapper:-soup-contains('Exclusivité')"
Résumé produit 3
| Priorité | Problème | Récurrent ? |
|---|---|---|
| 🟡 P2 | Choix Amazon faux positif (élément vide) | 🆕 Nouveau pattern |
| 🟢 P3 | Badge "Exclusivité Amazon" non capturé | Opportunité |
Note positive : Ce produit montre que le MSRP est correctement capturé quand il existe réellement sur la page produit (1699,99€). Le problème MSRP des produits 1 et 2 vient bien de prix barrés de produits tiers.
Produit 2 : Crucial Basics DDR4 8Go
URL: https://www.amazon.fr/dp/B0CWLSQ8FS
Comparaison: Données Amazon vs Données Scrapées
| Champ | Valeur Amazon (source) | Valeur Scrapée (Web UI) | Statut |
|---|---|---|---|
| Titre | Crucial Basics Mémoire pour Ordinateur de Bureau DDR4 3200 MT/s CL22 UDIMM 288 Broches 1,2 V 8 Go | Crucial Basics Mémoire pour Ordinateur de Bureau DDR4 3200 MT/s CL22 UDIMM 28... | ✅ OK |
| Prix | 80,00 € | 80 € | ✅ OK |
| Prix conseillé (MSRP) | Non affiché sur Amazon | 606,99 € | ❌ ERREUR |
| Stock | "Habituellement expédié sous 5 à 6 jours" | "Inconnu" | ❌ ERREUR |
| Note | 3,7 (27) | 3,7 (27) | ✅ OK |
| Choix Amazon | Non visible sur capture | Oui | ⚠️ À VÉRIFIER |
| Référence (ASIN) | B0CWLSQ8FS | B0CWLSQ8FS | ✅ OK |
| Image principale | Image RAM Crucial | Image RAM Crucial | ✅ OK |
Défauts identifiés
1. ❌ ERREUR: MSRP incorrect (606,99 €)
Problème: Le Web UI affiche "PRIX CONSEILLÉ: 606,99€" alors qu'Amazon n'affiche aucun prix conseillé pour ce produit à 80€.
Cause racine identifiée :
Le prix 606,99€ provient de la section "Découvrir et s'inspirer" (sims-discoveryAndInspiration_feature_div), un produit similaire/recommandé.
Source HTML: #CardInstance5M3xhZWYVx9FloZeghy3og
Section parente: #sims-discoveryAndInspiration_feature_div_01
Même problème que produit 1 : Le sélecteur MSRP (span.a-text-price span.a-offscreen) capture des prix barrés de produits tiers.
2. ❌ ERREUR: Stock "Inconnu" au lieu de "Expédié sous 5-6 jours"
Problème: Le stock est affiché comme "Inconnu" alors qu'Amazon indique clairement "Habituellement expédié sous 5 à 6 jours".
Données HTML :
#availability span: "Habituellement expédié sous 5 à 6 jours"
Cause racine :
Le parser ne reconnaît pas ce texte comme indicateur de stock. La méthode _extract_stock_details() cherche uniquement :
- "en stock" / "in stock" / "available" → IN_STOCK
- "rupture" / "indisponible" / "out of stock" → OUT_OF_STOCK
Le texte "expédié sous X jours" n'est pas mappé → retourne UNKNOWN.
Fichier concerné: store.py:304-326 - méthode _extract_stock_details()
Correction proposée :
# Ajouter la reconnaissance des délais d'expédition
if "expédié sous" in normalized or "dispatched within" in normalized:
return StockStatus.IN_STOCK, text, True # Expédié = disponible
3. ⚠️ AVERTISSEMENT: Choix Amazon potentiellement incorrect
Le Web UI affiche "CHOIX AMAZON: Oui" mais le badge n'est pas clairement visible sur la capture Amazon.
À vérifier : Le badge peut être présent dans le HTML mais non visible sur la capture d'écran.
Résumé produit 2
| Priorité | Problème | Récurrent ? |
|---|---|---|
| 🟠 P1 | MSRP incorrect (606,99€ d'un produit tiers) | ✅ Oui (même cause que produit 1) |
| 🟠 P1 | Stock "Inconnu" au lieu de "En stock (délai)" | 🆕 Nouveau pattern |
Produit 1 : Corsair Vengeance LPX DDR4 32Go
URL: https://www.amazon.fr/dp/B07RW6Z692?th=1
Comparaison: Données Amazon vs Données Scrapées
| Champ | Valeur Amazon (source) | Valeur Scrapée (Web UI) | Statut |
|---|---|---|---|
| Titre | Corsair Vengeance LPX DDR4 RAM 32Go (2x16Go) 3200MHz CL16 Intel XMP 2.0 Mémoire d'ordinateur - Noir (CMK32GX4M2E3200C16) | Corsair Vengeance LPX DDR4 RAM 32Go (2x16Go) 3200MHz CL16 Intel XMP 2.0... | ⚠️ TRONQUÉ |
| Prix | 230,54 € | 230,54 € | ✅ OK |
| Prix conseillé (MSRP) | Non affiché sur Amazon | 139 € | ❌ ERREUR |
| Stock | "Plus de 500 achetés au cours du mois dernier" (implicitement en stock) | "En stock" | ✅ OK |
| Note | 4,8 | 4,8 | ✅ OK |
| Nombre d'avis | 28 245 | 28 245 | ✅ OK |
| Choix Amazon | Oui (badge visible) | Oui | ✅ OK |
| Référence (ASIN) | B07RW6Z692 | B07RW6Z692 | ✅ OK |
| Image principale | Image RAM Corsair Vengeance | Image processeur AMD Ryzen 7 | ❌ ERREUR CRITIQUE |
| Catégorie | Mémoire RAM | Mémoire RAM | ✅ OK |
Défauts identifiés
1. ❌ ERREUR CRITIQUE: Mauvaise image produit
Problème: L'image affichée dans le Web UI est un processeur AMD Ryzen 7 5800X, alors que le produit est de la RAM Corsair Vengeance.
Cause racine identifiée :
L'image provient de la section "Fréquemment achetés ensemble" (_p13n-desktop-sims-fbt).
Image fautive: https://images-eu.ssl-images-amazon.com/images/I/61IIbwz-+ML._AC_UL116_SR116,116_.jpg
Contexte HTML: <a class="_p13n-desktop-sims-fbt_fbt-desktop_image-display__2oZhY asin-2">
Données en base :
ProductImage position=0 : 61IIbwz-+ML (Ryzen) ← INCORRECT
ProductImage position=1 : 61wCOVcyvFL (Corsair RAM) ← CORRECT
Explication :
- Le sélecteur
.a-dynamic-imagecapture toutes les images dynamiques de la page - L'image du Ryzen (dans "Fréquemment achetés ensemble") est trouvée AVANT l'image principale du produit
- Elle est donc insérée en position 0 (image principale)
Fichier concerné: store.py:328-378 - méthode _extract_images()
Correction proposée :
- Prioriser
#landingImagecomme source unique pour l'image principale - Filtrer les images provenant de sections publicitaires (
_p13n-,sp_detail,sims-fbt) - Ne pas utiliser
.a-dynamic-imageseul car trop large
2. ❌ ERREUR: Prix conseillé (MSRP) incorrect
Problème: Le Web UI affiche "PRIX CONSEILLÉ: 139€" alors qu'Amazon n'affiche aucun prix barré/conseillé pour ce produit.
Cause racine identifiée : Le prix 139€ provient d'un produit sponsorisé affiché sur la page.
Source HTML: <div id="sp_detail2_B0FNMQQK58" class="sp_offerVertical p13n-asin sp_ltr_offer">
Texte: "Conseillé : 139,00 €"
Données en base :
Product.msrp = 139.00 ← Valeur stockée incorrecte
Parser actuel (test aujourd'hui) :
snapshot.msrp = None ← Le parser actuel retourne correctement None
Explication :
- Un scraping précédent a capté ce prix sponsorisé comme MSRP
- Le sélecteur
span.a-text-price span.a-offscreenest trop générique - Il capture n'importe quel prix barré de la page (pubs, suggestions, etc.)
Fichier concerné: store.py:276-285 - méthode _extract_msrp()
Correction proposée :
- Restreindre la recherche MSRP au conteneur principal du produit (
#corePrice_feature_div,#apex_desktop) - Exclure explicitement les sections sponsorisées (
#sp_detail,.sp_offerVertical) - Ajouter une validation : MSRP > prix actuel (sinon, ignorer)
3. ⚠️ AVERTISSEMENT: Titre tronqué
Problème: Le titre complet inclut "(CMK32GX4M2E3200C16)" qui semble coupé dans l'affichage.
Données en base :
Product.title = "Corsair Vengeance LPX DDR4 RAM 32Go (2x16Go) 3200MHz CL16 Intel XMP 2.0 Mémoire d'ordinateur - Noir (CMK32GX4M2E3200C16)"
Verdict : Le titre est complet en base. C'est un problème d'affichage UI (CSS truncation), pas de scraping.
4. ℹ️ DONNÉES NON SCRAPÉES (opportunités)
| Donnée Amazon | Présence | Priorité |
|---|---|---|
| Prix en 4x (58,96€ x4 mois) | ❌ | Basse |
| "Frais d'importation Inclus" | ❌ | Moyenne |
| Marque: Corsair | ❌ (dans specs) | Basse |
| Specs techniques (DDR4, 32Go, 3200MHz) | ✅ (table specs) | - |
| "Plus de 500 achetés" | ❌ | Basse |
| Options de taille (variantes) | ❌ | Haute |
Analyse technique approfondie
État actuel du parser (test du 2026-01-18)
# Résultat du parsing sur HTML frais
snapshot.title = "Corsair Vengeance LPX DDR4..." ✅
snapshot.price = 230.54 ✅
snapshot.msrp = None ✅ (correct!)
snapshot.main_image = "61wCOVcyvFL" ✅ (image RAM correcte)
snapshot.rating_value = 4.8 ✅
snapshot.rating_count = 28246 ✅
snapshot.amazon_choice = True ✅
Conclusion : Le parser actuel fonctionne correctement. Les erreurs proviennent de données historiques en base issues d'un scraping précédent bugué.
Données corrompues en base
| Table | Champ | Valeur actuelle | Valeur attendue |
|---|---|---|---|
products |
msrp |
139.00 | NULL |
product_images |
position=0 | 61IIbwz-+ML (Ryzen) | 61wCOVcyvFL (RAM) |
Résumé des priorités
| Priorité | Problème | Action requise |
|---|---|---|
| 🔴 P0 | Image principale incorrecte en BDD | Nettoyer les données + corriger l'extraction |
| 🟠 P1 | MSRP incorrect en BDD | Nettoyer les données + restreindre le sélecteur MSRP |
| 🟢 P2 | Parser actuel OK | Valider que les corrections persistent |
Recommandations d'amélioration
1. Correction extraction images
# Prioriser #landingImage uniquement pour l'image principale
landing = soup.select_one('#landingImage')
if landing:
main_image = landing.get('data-old-hires') or landing.get('src')
# Filtrer les images de sections publicitaires
EXCLUDED_PARENTS = ['_p13n-', 'sp_detail', 'sims-fbt', 'sponsored']
def _is_product_image(self, element) -> bool:
for parent in element.parents:
classes = ' '.join(parent.get('class', []))
if any(excl in classes for excl in EXCLUDED_PARENTS):
return False
return True
2. Correction extraction MSRP
# Restreindre au conteneur principal
price_container = soup.select_one('#corePrice_feature_div, #apex_desktop')
if price_container:
msrp_element = price_container.select_one('span.a-text-price span.a-offscreen')
# Validation : MSRP doit être > prix actuel
if msrp and price and msrp <= price:
msrp = None # Ignorer les valeurs incohérentes
3. Migration données existantes
-- Corriger le MSRP incorrect
UPDATE products SET msrp = NULL WHERE reference = 'B07RW6Z692' AND msrp = 139.00;
-- Supprimer l'image Ryzen incorrecte
DELETE FROM product_images
WHERE product_id = (SELECT id FROM products WHERE reference = 'B07RW6Z692')
AND image_url LIKE '%61IIbwz%';
-- Réordonner les positions
UPDATE product_images SET position = position - 1
WHERE product_id = (SELECT id FROM products WHERE reference = 'B07RW6Z692')
AND position > 0;
Fichiers à modifier
-
store.py - Logique d'extraction Amazon
_extract_images(): filtrer les sections publicitaires_extract_msrp(): restreindre au conteneur principal
-
selectors.yml - Ajouter sélecteurs exclusion
-
Migration SQL - Nettoyer les données corrompues existantes
Prochaines étapes
- ✅ Identifier les causes racines (fait)
- ⬜ Implémenter les corrections dans le parser
- ✅ Nettoyer les données corrompues en base → Workaround actuel : suppression + ré-ajout du produit
- ⬜ Re-scraper le produit pour valider
- ⬜ Tester sur d'autres produits Amazon
Note importante
Workaround temporaire : La correction des données corrompues se fait actuellement par suppression puis ré-ajout du produit depuis le Web UI. Cela fonctionne car le parser actuel est correct.
Limitation : Cette méthode supprime l'historique des prix du produit. Une correction du parser reste nécessaire pour éviter de futures corruptions.
Plan de corrections
1. Infrastructure : Installer Playwright
playwright install
Impact : Évite le fallback HTTP qui capture des MSRP incorrects.
1bis. Stratégie de fetch : Playwright prioritaire pour Amazon
Constat
| Méthode | Avantage | Inconvénient pour Amazon |
|---|---|---|
| HTTP | Rapide | HTML contient plus de sections sponsorisées/recommandations |
| Playwright | HTML "propre" après JS | Plus lent |
Flux actuel
HTTP d'abord → Si échec → Playwright (fallback)
Flux proposé pour Amazon
Playwright d'abord → Si échec → HTTP (fallback)
Implémentation
Ajouter une propriété prefer_playwright dans BaseStore :
# pricewatch/app/stores/base.py
class BaseStore:
prefer_playwright: bool = False # Par défaut HTTP first
# pricewatch/app/stores/amazon/store.py
class AmazonStore(BaseStore):
prefer_playwright: bool = True # Playwright first pour Amazon
Modifier scrape_product() dans tasks/scrape.py :
# Déterminer l'ordre de fetch selon le store
if store.prefer_playwright and use_playwright:
# Playwright d'abord
pw_result = fetch_playwright(...)
if pw_result.success:
html = pw_result.html
fetch_method = FetchMethod.PLAYWRIGHT
else:
# Fallback HTTP
http_result = fetch_http(...)
...
else:
# HTTP d'abord (comportement actuel)
...
1ter. Vérification du flux UI preview/commit
Constat
Le flux preview/commit existe déjà et fonctionne correctement :
| Action UI | Endpoint | Persistence |
|---|---|---|
| "Ajouter" → Preview | /scrape/preview |
❌ Non (save_db=False) |
| "Enregistrer" → Commit | /scrape/commit |
✅ Oui |
Conclusion : Pas de modification nécessaire côté UI. Les données sont bien persistées uniquement sur action explicite de l'utilisateur.
2. Parser : Restreindre extraction MSRP
Fichier : store.py
Problème identifié (Produit 8 - UGREEN)
Le parser utilise select_one() qui retourne le premier élément trouvé. Or Amazon affiche maintenant :
Prix actuel: 118,99€
Prix le plus bas des 30 derniers jours: 127,49€ ← PREMIER dans le DOM
Prix conseillé: 169,99€ (-30%) ← SECOND dans le DOM
Résultat : Le parser capture 127,49€ (prix bas 30j) au lieu de 169,99€ (MSRP).
Analyse HTML réelle
# Ordre des éléments span.a-text-price span.a-offscreen dans #corePriceDisplay_desktop_feature_div:
# 0: 127,49€ ← Prix le plus bas 30 jours (directive Omnibus UE)
# 1: 169,99€ ← Prix conseillé (MSRP réel)
Structure HTML identifiée
Les deux prix sont dans des sections distinctes avec des classes CSS spécifiques :
<!-- Prix le plus bas 30 jours (directive Omnibus UE) -->
<span class="basisPrice">
"Prix le plus bas des 30 derniers jours : "
<span class="a-price a-text-price" data-a-strike="true">
<span class="a-offscreen">127,49€</span>
</span>
</span>
<!-- Prix conseillé (MSRP) -->
<span class="srpPriceBlock">
"Prix conseillé : "
<span class="a-price a-text-price srpPriceBlockAUI">
<span class="a-offscreen">169,99€</span>
</span>
</span>
<span class="srpSavingsPercentageBlock">-30%</span>
Classes identifiantes
| Élément | Classe CSS | Contenu |
|---|---|---|
| Prix bas 30j | basisPrice |
Prix le plus bas des 30 derniers jours |
| MSRP | srpPriceBlock, srpPriceBlockAUI |
Prix conseillé |
Correction proposée (méthode précise)
def _extract_msrp(self, soup, debug):
"""Extrait le prix conseillé (MSRP) via les classes CSS spécifiques."""
# Méthode 1: Cibler directement srpPriceBlock (plus précis)
srp_block = soup.select_one('span.srpPriceBlock .a-offscreen, span.srpPriceBlockAUI .a-offscreen')
if srp_block:
return parse_price_text(srp_block.get_text(strip=True))
# Méthode 2: Fallback - chercher dans le conteneur prix en excluant basisPrice
price_container = soup.select_one('#corePriceDisplay_desktop_feature_div, #corePrice_feature_div, #apex_desktop')
if price_container:
for strike in price_container.select('span.a-text-price span.a-offscreen'):
# Exclure les prix dans basisPrice (prix bas 30j)
if not strike.find_parent(class_='basisPrice'):
return parse_price_text(strike.get_text(strip=True))
return None
Avantages de cette approche
| Approche | Avantage | Inconvénient |
|---|---|---|
max() des prix |
Simple | Peut échouer si MSRP < prix bas 30j (rare) |
Cibler srpPriceBlock |
Précis, robuste | Dépend de la classe CSS Amazon |
Exclure basisPrice |
Fiable | Fallback si srpPriceBlock absent |
Recommandation : Combiner les deux méthodes (cibler srpPriceBlock en priorité, fallback avec exclusion basisPrice).
3. Parser : Reconnaître "expédié sous" comme stock disponible
Fichier : store.py
def _extract_stock_details(self, soup, debug):
# ... code existant ...
normalized = text.lower()
# Ajouter reconnaissance délai d'expédition
if "expédié sous" in normalized or "dispatched within" in normalized:
return StockStatus.IN_STOCK, text, True
# Ajouter reconnaissance bouton panier si #availability vide
if not text and soup.select_one('#add-to-cart-button'):
return StockStatus.IN_STOCK, "Disponible", True
4. Parser : Corriger détection Amazon Choice
Fichier : store.py
def _extract_amazon_choice(self, soup, debug):
element = soup.select_one('#acBadge_feature_div')
if element:
text = element.get_text(strip=True)
# Ne retourner True que si le texte contient vraiment le badge
if text and ("choix d'amazon" in text.lower() or "amazon's choice" in text.lower()):
return True, text
return None, None
5. UI : Ne pas afficher "Stock: Inconnu"
Si le stock n'est pas détecté, ne pas afficher la ligne plutôt que "Inconnu".
6. UI : Supprimer "EVOL. 30 JOURS"
Cette donnée est calculée, pas scrapée. Elle ne doit pas apparaître dans le bloc d'informations produit.
7. Classification : Améliorer règles de type
| Mot-clé actuel | Problème | Correction |
|---|---|---|
| "GeForce", "RTX" → Ecran | Carte graphique mal classée | Ajouter règle "Carte graphique" |
| "SODIMM" → PC portable | RAM mal classée | Prioriser "RAM" si DDR présent |
Checklist de validation
- Playwright installé et fonctionnel
- MSRP = None pour produits sans prix barré sur Amazon
- MSRP > prix actuel (validation obligatoire)
- Stock "expédié sous X jours" → En stock
- Amazon Choice = False si élément vide
- UI ne montre pas "Stock: Inconnu"
- UI ne montre pas "EVOL. 30 JOURS"
- Classification correcte GPU / RAM
SYNTHÈSE FINALE
Produits analysés
| # | Produit | ASIN | Erreurs principales |
|---|---|---|---|
| 1 | Corsair Vengeance LPX DDR4 32Go | B07RW6Z692 | MSRP incorrect (139€), Image incorrecte (Ryzen) |
| 2 | Crucial Basics DDR4 8Go | B0CWLSQ8FS | MSRP incorrect (606,99€), Stock "Inconnu" |
| 3 | ASUS TUF Gaming A16 | B0DQ8M74KL | Amazon Choice faux positif |
| 4 | MSI RTX 5060 Ti | B0F32N1ZGH | MSRP incorrect (102,99€), Type "Ecran" |
| 5 | Samsung SSD 9100 Pro | B0DWFLPMM5 | Stock "Inconnu" (produit disponible) |
| 6 | Corsair Vengeance SODIMM 32Go | B08GSTF5NJ | MSRP incorrect (606,99€), Type "PC portable" |
| 7 | MSI Modern MD2412P Écran | B0CB4FDJT5 | ✅ OK (MSRP correct car affiché sur Amazon) |
| 8 | UGREEN Revodok Pro | B0FGHX59G2 | MSRP = prix bas 30j (127,49€), Amazon Choice faux positif, Type "Ecran" |
| 9 | Anker Prime Battery | B0BYNZXFM2 | MSRP < prix (39,99€ < 99,99€), Amazon Choice faux positif |
Statistiques : 8/9 produits avec erreurs, 1/9 correct
Erreurs identifiées et solutions
🔴 ERREUR 1 : MSRP incorrect (prix de produits tiers)
Fréquence : 6/9 produits
Symptômes :
- MSRP provient de produits sponsorisés (
#sp_detail_*) - MSRP provient de recommandations (
#CardInstance*,#sims-*) - MSRP < prix actuel (absurde)
Causes :
- Sélecteur
span.a-text-price span.a-offscreentrop large (toute la page) select_one()prend le 1er élément trouvé (peut être prix bas 30j)- Fallback HTTP expose plus de sections sponsorisées que Playwright
Solutions :
def _extract_msrp(self, soup, debug, current_price):
# 1. Cibler directement la classe srpPriceBlock
srp = soup.select_one('span.srpPriceBlock .a-offscreen, span.srpPriceBlockAUI .a-offscreen')
if srp:
msrp = parse_price_text(srp.get_text(strip=True))
if msrp and current_price and msrp > current_price:
return msrp
# 2. Fallback: conteneur principal, exclure basisPrice
container = soup.select_one('#corePriceDisplay_desktop_feature_div, #corePrice_feature_div')
if container:
for strike in container.select('span.a-text-price span.a-offscreen'):
if not strike.find_parent(class_='basisPrice'):
msrp = parse_price_text(strike.get_text(strip=True))
if msrp and current_price and msrp > current_price:
return msrp
return None # Pas de MSRP valide
Validation obligatoire : MSRP > prix actuel (sinon ignorer)
🔴 ERREUR 2 : Amazon Choice faux positif
Fréquence : 3/9 produits
Symptôme : "CHOIX AMAZON: Oui" alors qu'aucun badge visible
Cause : L'élément #acBadge_feature_div existe dans le DOM mais est vide
Solution :
def _extract_amazon_choice(self, soup, debug):
element = soup.select_one('#acBadge_feature_div')
if element:
text = element.get_text(strip=True)
# Vérifier que le texte contient vraiment le badge
if text and ("choix d'amazon" in text.lower() or "amazon's choice" in text.lower()):
return True, text
return None, None # Pas de badge
🟠 ERREUR 3 : Stock "Inconnu" affiché
Fréquence : 3/9 produits
Symptômes :
- "Habituellement expédié sous 5-6 jours" → Stock "Inconnu"
- Produit disponible (bouton panier) mais
#availabilityvide → Stock "Inconnu"
Causes :
- Parser ne reconnaît pas "expédié sous" comme indicateur de disponibilité
- UI affiche "Inconnu" au lieu de masquer le champ
Solutions :
Parser :
def _extract_stock_details(self, soup, debug):
# Reconnaître délai d'expédition
if "expédié sous" in normalized or "dispatched within" in normalized:
return StockStatus.IN_STOCK, text, True
# Détecter disponibilité via bouton panier
if not text and soup.select_one('#add-to-cart-button'):
return StockStatus.IN_STOCK, "Disponible", True
UI : Ne pas afficher "Stock: Inconnu" - masquer le champ si non détecté
🟠 ERREUR 4 : "EVOL. 30 JOURS" affiché
Fréquence : 9/9 produits (tous)
Symptôme : UI affiche "+0.0%" ou autre valeur calculée
Cause : Donnée calculée côté frontend, non scrapée
Règle : Seules les données présentes sur Amazon doivent être affichées
Solution : Supprimer la ligne "EVOL. 30 JOURS" du bloc d'informations produit
🟡 ERREUR 5 : Classification de type incorrecte
Fréquence : 3/9 produits
Exemples :
- Carte graphique RTX → "Ecran"
- RAM SODIMM → "PC portable"
- Docking station → "Ecran"
Cause : Règles de classification par mots-clés trop simplistes
Solutions :
| Mot-clé | Classification actuelle | Classification correcte |
|---|---|---|
| RTX, GeForce, Radeon | Ecran | Carte graphique |
| DDR4, DDR5, SODIMM, DIMM | PC portable | RAM / Mémoire |
| DisplayPort, HDMI (seul) | Ecran | Vérifier contexte (docking ≠ écran) |
🟡 ERREUR 6 : Playwright non installé
Symptôme : Erreur Executable doesn't exist at /root/.cache/ms-playwright/chromium_headless_shell-1200
Impact : Fallback HTTP capture plus d'erreurs MSRP
Solution :
playwright install
Priorités de correction
| Priorité | Correction | Impact | Effort |
|---|---|---|---|
| 🔴 P0 | Restreindre extraction MSRP + validation | 6 produits corrigés | Moyen |
| 🔴 P0 | Corriger détection Amazon Choice | 3 produits corrigés | Faible |
| 🟠 P1 | Installer Playwright | Réduit erreurs MSRP | Faible |
| 🟠 P1 | Améliorer détection stock | 3 produits corrigés | Faible |
| 🟠 P1 | Supprimer "EVOL. 30 JOURS" de l'UI | 9 produits corrigés | Faible |
| 🟡 P2 | Améliorer classification types | 3 produits corrigés | Moyen |
| 🟡 P2 | Masquer "Stock: Inconnu" dans l'UI | UX améliorée | Faible |
Fichiers impactés par les corrections
Backend - Parser Amazon
| Fichier | Fonction/Section | Modification | Erreur corrigée |
|---|---|---|---|
| store.py | _extract_msrp() (L276-285) |
Cibler srpPriceBlock, exclure basisPrice, valider MSRP > prix |
ERREUR 1 |
| store.py | _extract_amazon_choice() (L496-520) |
Vérifier texte non vide avant retourner True | ERREUR 2 |
| store.py | _extract_stock_details() (L304-326) |
Reconnaître "expédié sous", détecter bouton panier | ERREUR 3 |
| selectors.yml | Section msrp |
Ajouter srpPriceBlock, srpPriceBlockAUI, basisPrice |
ERREUR 1 |
Backend - Infrastructure
| Fichier | Fonction/Section | Modification | Erreur corrigée |
|---|---|---|---|
| base.py | Classe BaseStore |
Ajouter attribut prefer_playwright: bool = False |
ERREUR 6 |
| store.py | Classe AmazonStore |
Définir prefer_playwright = True |
ERREUR 6 |
| scrape.py | scrape_product() (L83-118) |
Inverser ordre fetch si store.prefer_playwright |
ERREUR 6 |
Frontend - Web UI
| Fichier | Fonction/Section | Modification | Erreur corrigée |
|---|---|---|---|
| App.vue | Template carte produit | Supprimer ligne "EVOL. 30 JOURS" | ERREUR 4 |
| App.vue | Template carte produit | Masquer "Stock: Inconnu" (afficher seulement si stock connu) | ERREUR 3 |
Base de données - Classification
| Fichier | Table/Section | Modification | Erreur corrigée |
|---|---|---|---|
| repository.py | apply_classification() |
Vérifier règles de classification | ERREUR 5 |
Table classification_rules |
Données | Ajouter règle "Carte graphique" (RTX, GeForce, Radeon) | ERREUR 5 |
Table classification_rules |
Données | Ajouter règle "RAM / Mémoire" (DDR4, DDR5, SODIMM, DIMM) | ERREUR 5 |
Table classification_rules |
Données | Modifier règle "Ecran" (exclure si contexte docking/carte graphique) | ERREUR 5 |
Matrice de traçabilité Erreur → Fichiers
| Erreur | Fichiers impactés |
|---|---|
| ERREUR 1 : MSRP incorrect | store.py, selectors.yml |
| ERREUR 2 : Amazon Choice faux positif | store.py |
| ERREUR 3 : Stock "Inconnu" | store.py, App.vue |
| ERREUR 4 : "EVOL. 30 JOURS" | App.vue |
| ERREUR 5 : Classification type | repository.py, table classification_rules |
| ERREUR 6 : Playwright non installé | base.py, store.py (Amazon), scrape.py |
Ordre de modification recommandé
-
Installer Playwright (prérequis)
playwright install -
Parser Amazon (
store.py)_extract_msrp()- correction principale_extract_amazon_choice()- correction simple_extract_stock_details()- amélioration
-
Sélecteurs (
selectors.yml)- Ajouter nouveaux sélecteurs MSRP
-
Web UI (
App.vue)- Supprimer "EVOL. 30 JOURS"
- Masquer "Stock: Inconnu"
-
Classification (BDD +
repository.py)- Ajouter règles manquantes
- Ajuster priorités
-
Infrastructure fetch (
base.py,scrape.py)- Optionnel : Playwright prioritaire pour Amazon
Conclusion
L'analyse de 9 produits Amazon a révélé des erreurs systématiques principalement liées à :
-
Extraction MSRP trop permissive - Le parser capture des prix de produits tiers car le sélecteur n'est pas restreint au bloc prix principal
-
Détection Amazon Choice sans validation - Le parser retourne
Truesi l'élément existe, même s'il est vide -
Affichage de données calculées - L'UI affiche des données non présentes sur Amazon
Les corrections proposées sont relativement simples à implémenter et corrigeraient 8/9 produits testés. Le produit 7 (MSI Écran) était déjà correct car il possède un vrai MSRP affiché sur Amazon.
PROPOSITION DE CORRECTION VALIDÉE
1. MSRP – extraction trop permissive
Problème : Le sélecteur global span.a-text-price span.a-offscreen attrape des prix barrés dans des sections non-produit (sponsorisé, recommandations, "prix bas 30j").
Solution détaillée (backend) :
- Cibler d'abord la zone prix du produit principal :
#corePriceDisplay_desktop_feature_div,#corePrice_feature_div,#apex_desktop - Dans ce conteneur, prioriser
span.srpPriceBlock .a-offscreenouspan.srpPriceBlockAUI .a-offscreen - Exclure
basisPrice(directive Omnibus "prix bas 30 jours") - Validation métier obligatoire : ignorer MSRP si
msrp <= price(ou si price absent)
Cas limites :
- MSRP présent mais prix courant absent (produit indisponible) → garder MSRP si cohérent, mais marquer debug
- MSRP en devise/format inattendu → garder
Noneet tracer
Fichiers : store.py, selectors.yml
2. MSRP – 1er match "prix bas 30j"
Problème : select_one() prend le premier prix barré, parfois le "prix bas 30j".
Solution détaillée :
- Si
srpPriceBlockabsent, parcourir tous lesspan.a-text-price span.a-offscreendu conteneur prix - Exclure ceux dont un parent a la classe
basisPrice - Si plusieurs candidats, prendre le plus élevé uniquement si price est présent et
msrp > price
Fichier : store.py
3. Amazon Choice faux positif
Problème : #acBadge_feature_div existe mais vide → renvoyé True.
Solution détaillée :
- Vérifier texte non vide + correspondance stricte ("choix d'amazon" ou "amazon's choice")
- Si vide →
False+ conserver debug avec le DOM trouvé
Fichier : store.py
4. Stock – "expédié sous X jours"
Problème : Texte d'expédition n'est pas reconnu comme dispo.
Solution détaillée :
- Normaliser le texte (
lower(),strip()) - Pattern matching :
expédié sous,habituellement expédié sous,dispatched within→IN_STOCK- Si
#availabilityvide mais#add-to-cart-buttonprésent →IN_STOCK("Disponible")
- UI : si le statut reste
UNKNOWN, ne rien afficher
Fichiers : store.py, App.vue
5. Images – mauvaise image principale
Problème : .a-dynamic-image agrège images de sections tiers (sims, fbt, ads).
Solution détaillée :
- Prioriser
#landingImage(ouimg#imgTagWrapperId img) - Filtrer toute image dont un parent contient
_p13n-,sims-fbt,sp_detail,sponsored - Garder un fallback seulement si
landingImageabsent
Fichier : store.py
6. UI – "EVOL. 30 JOURS"
Problème : Info calculée non présente sur Amazon.
Solution détaillée : Retirer ce champ du bloc produit et garder l'historique dans le graphique si besoin.
Fichier : App.vue
7. Fetch Amazon – Playwright prioritaire
Problème : Fallback HTTP expose plus de sections sponsorisées.
Solution détaillée :
- Attribut
prefer_playwrightdansBaseStore - Inverser l'ordre dans
scrape_product()si store le demande
Risque : Temps de scraping plus long, besoin de navigateur installé.
Fichiers : base.py, store.py, scrape.py
8. Classification – type incorrect
Problème : Règles mots-clés trop générales.
Solution détaillée :
- Règles prioritaires :
- GPU :
RTX|GeForce|Radeon|GPU|Carte graphique - RAM :
DDR4|DDR5|SODIMM|DIMM|mémoire - Docking :
dock|hub|station→ ne pas classer en "Ecran"
- GPU :
- Appliquer priorité stricte (GPU > écran, RAM > PC portable)
Fichiers : repository.py et/ou table classification_rules
9. Données corrompues existantes
Problème : MSRP et image déjà stockés incorrectement.
Solution détaillée :
- Migration ou script de correction ciblée (par ASIN)
- Alternative : purge + re-scrape (perte historique)
Fichiers : SQL ou script dédié (à définir)
Plan d'implémentation recommandé
Phase 1 : Corrections critiques (P0)
| Étape | Action | Fichier | Test |
|---|---|---|---|
| 1.1 | Installer Playwright | Terminal | playwright install |
| 1.2 | Corriger _extract_msrp() |
store.py |
Produits 1,2,4,6,8,9 |
| 1.3 | Corriger _extract_amazon_choice() |
store.py |
Produits 3,8,9 |
| 1.4 | Ajouter sélecteurs MSRP | selectors.yml |
- |
Phase 2 : Corrections importantes (P1)
| Étape | Action | Fichier | Test |
|---|---|---|---|
| 2.1 | Corriger _extract_stock_details() |
store.py |
Produits 2,5 |
| 2.2 | Corriger _extract_images() |
store.py |
Produit 1 |
| 2.3 | Supprimer "EVOL. 30 JOURS" | App.vue |
Tous produits |
| 2.4 | Masquer "Stock: Inconnu" | App.vue |
Produits 2,5 |
Phase 3 : Améliorations (P2)
| Étape | Action | Fichier | Test |
|---|---|---|---|
| 3.1 | Ajouter règles classification | BDD | Produits 4,6,8 |
| 3.2 | Ajouter prefer_playwright |
base.py, scrape.py |
Amazon |
| 3.3 | Script correction données | SQL | Produits existants |
Validation finale
Après implémentation, re-tester les 9 produits :
| # | ASIN | Erreurs avant | Attendu après |
|---|---|---|---|
| 1 | B07RW6Z692 | MSRP, Image | ✅ OK |
| 2 | B0CWLSQ8FS | MSRP, Stock | ✅ OK |
| 3 | B0DQ8M74KL | Amazon Choice | ✅ OK |
| 4 | B0F32N1ZGH | MSRP, Type | ✅ OK |
| 5 | B0DWFLPMM5 | Stock | ✅ OK |
| 6 | B08GSTF5NJ | MSRP, Type | ✅ OK |
| 7 | B0CB4FDJT5 | ✅ OK | ✅ OK |
| 8 | B0FGHX59G2 | MSRP, Amazon Choice, Type | ✅ OK |
| 9 | B0BYNZXFM2 | MSRP, Amazon Choice | ✅ OK |