# Fixtures AliExpress Ce dossier contient des fichiers HTML réels capturés depuis AliExpress pour les tests. ## ⚠️ Note importante sur AliExpress AliExpress utilise un **rendu client-side (SPA React/Vue)**: - HTTP simple retourne **HTML minimal** (75KB sans contenu) - **Playwright est OBLIGATOIRE** avec attente (~3s) - Attendre le sélecteur `.product-title` pour obtenir les données - Données chargées via **AJAX** après le render initial ## Spécificité AliExpress AliExpress est un **marketplace chinois** avec des particularités: - **Pas de JSON-LD** schema.org - **Prix**: Extrait par **regex** (aucun sélecteur CSS stable) - **Images**: Extraites depuis `window._d_c_.DCData.imagePathList` (JSON embarqué) - **Classes CSS**: Générées aléatoirement (hachées) → **TRÈS instables** - **SKU**: ID numérique long (13 chiffres) depuis l'URL ## Fichiers ### aliexpress_1005007187023722.html - **Produit**: Samsung serveur DDR4 mémoire Ram ECC - **SKU**: 1005007187023722 - **URL**: https://fr.aliexpress.com/item/1005007187023722.html - **Taille**: 378 KB (rendu complet) - **Date capture**: 2026-01-13 - **Méthode**: Playwright avec wait_for_selector='.product-title' - **Prix capturé**: 136,69 EUR - **Usage**: Test complet parsing produit électronique ## Structure HTML AliExpress ### JSON-LD Schema.org ✗ AliExpress **n'utilise PAS** JSON-LD (contrairement à Backmarket). ### Données embarquées ✓ AliExpress embarque les données dans des variables JavaScript: ```javascript window._d_c_.DCData = { "imagePathList": ["https://ae01.alicdn.com/kf/..."], "summImagePathList": ["https://ae01.alicdn.com/kf/..."], "i18nMap": {...}, "extParams": {...} } ``` ### Sélecteurs identifiés #### Titre ```css h1 /* Apparaît après AJAX */ meta[property="og:title"] /* Fallback dans meta tags */ ``` Le h1 n'existe PAS dans le HTML initial, il est ajouté dynamiquement. #### Prix ⚠️ **AUCUN SÉLECTEUR CSS STABLE** - Utiliser regex: ```regex ([0-9]+[.,][0-9]{2})\s*€ /* Prix avant € */ €\s*([0-9]+[.,][0-9]{2}) /* € avant prix */ ``` #### Images Priorité: **window._d_c_.DCData.imagePathList** Fallback: `meta[property="og:image"]` URLs CDN: `https://ae01.alicdn.com/kf/...` #### SKU Extraction depuis l'URL: ```regex /item/(\d+)\.html ``` Exemple: `/item/1005007187023722.html` → SKU = "1005007187023722" #### Stock Chercher bouton "Add to cart" / "Ajouter au panier" ```css button[class*='add-to-cart'] ``` ## Comparaison avec autres stores | Aspect | Amazon | Cdiscount | Backmarket | **AliExpress** | |--------|--------|-----------|------------|----------------| | **Anti-bot** | Faible | Fort | Fort | Moyen | | **Méthode** | HTTP OK | Playwright | Playwright | **Playwright** | | **JSON-LD** | Partiel | ✗ Non | ✓ Oui | **✗ Non** | | **Sélecteurs** | Stables (IDs) | Instables | Stables | **Très instables** | | **SKU format** | `/dp/{ASIN}` | `/f-{cat}-{SKU}` | `/p/{slug}` | **/item/{ID}.html** | | **Prix extraction** | CSS | CSS/Regex | JSON-LD | **Regex uniquement** | | **Rendu** | Server-side | Server-side | Server-side | **Client-side (SPA)** | | **Particularité** | - | Prix dynamiques | Reconditionné | **SPA React/Vue** | ## Utilisation dans les tests ```python @pytest.fixture def aliexpress_fixture_samsung(): fixture_path = Path(__file__).parent.parent.parent / \ "pricewatch/app/stores/aliexpress/fixtures/aliexpress_1005007187023722.html" with open(fixture_path, "r", encoding="utf-8") as f: return f.read() def test_parse_real_fixture(store, aliexpress_fixture_samsung): url = "https://fr.aliexpress.com/item/1005007187023722.html" snapshot = store.parse(aliexpress_fixture_samsung, url) assert snapshot.title.startswith("Samsung serveur DDR4") assert snapshot.price == 136.69 assert snapshot.reference == "1005007187023722" assert snapshot.currency == "EUR" assert len(snapshot.images) >= 6 ``` ## Points d'attention pour les tests 1. **HTML volumineux** - 378KB pour une page (SPA chargée) 2. **Prix instable** - Peut changer selon promo/devise 3. **Ne pas tester le prix exact** - Tester le format et la présence 4. **Images multiples** - Toujours 6+ images par produit 5. **Titre long** - Souvent 100-150 caractères 6. **Stock variable** - Peut changer rapidement ## Comment capturer une nouvelle fixture ```python from pricewatch.app.scraping.pw_fetch import fetch_playwright url = "https://fr.aliexpress.com/item/..." result = fetch_playwright( url, headless=True, timeout_ms=15000, wait_for_selector=".product-title" # IMPORTANT! ) if result.success: with open("fixture.html", "w", encoding="utf-8") as f: f.write(result.html) ``` ⚠️ **N'utilisez PAS** `fetch_http()` - il retourne un HTML minimal (75KB)! ⚠️ **Utilisez TOUJOURS** `wait_for_selector=".product-title"` avec Playwright! ## Avantages de AliExpress ✓ **HTTP fonctionne** → Pas d'anti-bot fort (mais HTML vide) ✓ **Données embarquées** → DCData JSON avec images ✓ **SKU simple** → ID numérique depuis URL ## Inconvénients ✗ **SPA client-side** → Playwright obligatoire avec wait (~3-5s) ✗ **Pas de JSON-LD** → Extraction moins fiable ✗ **Prix par regex** → Fragile, peut casser ✗ **Classes CSS instables** → Générées aléatoirement (hachées) ✗ **Temps de chargement** → 3-5s avec Playwright + wait ✗ **Specs mal structurées** → Souvent dans des onglets/modals