Files
scrap/pricewatch/app/stores/aliexpress/fixtures/README.md
2026-01-13 19:49:04 +01:00

164 lines
5.4 KiB
Markdown
Executable File

# 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