164 lines
5.4 KiB
Markdown
Executable File
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
|