12 KiB
Executable File
Analyse Store Backmarket
Date: 2026-01-13 Auteur: PriceWatch Development Team
Résumé Exécutif
Backmarket.fr est un marketplace de produits reconditionnés (smartphones, laptops, tablets, etc.). Le parsing est très fiable grâce à l'utilisation extensive de JSON-LD schema.org, mais nécessite Playwright obligatoire en raison de la protection anti-bot.
Score de parsing: ⭐⭐⭐⭐⭐ (5/5) - Excellent Difficulté d'accès: 🔒🔒🔒 (3/5) - Anti-bot fort
🎯 Spécificités Backmarket
1. Marketplace de Reconditionné
Contrairement à Amazon ou Cdiscount qui vendent du neuf, Backmarket vend exclusivement du reconditionné.
Implications:
- Chaque produit a plusieurs offres avec différents états/conditions
- Prix variable selon la condition choisie (Correct, Bon, Excellent, etc.)
- Le grade/condition doit être extrait et stocké dans
specs["Condition"]
Grades Backmarket:
- Correct - État correct avec traces d'usage visibles
- Bon - Quelques rayures légères
- Très bon - Très peu de rayures
- Excellent - Quasiment aucune trace d'usage
- Comme neuf - État neuf
2. Protection Anti-bot Forte
❌ HTTP simple ne fonctionne PAS - retourne 403 Forbidden ✅ Playwright OBLIGATOIRE pour récupérer le contenu
# ❌ NE FONCTIONNE PAS
result = fetch_http("https://www.backmarket.fr/fr-fr/p/iphone-15-pro")
# → 403 Forbidden
# ✅ FONCTIONNE
result = fetch_playwright("https://www.backmarket.fr/fr-fr/p/iphone-15-pro", headless=True)
# → 200 OK avec contenu complet
Temps de chargement: ~2-3 secondes avec Playwright
📊 Structure HTML & Extraction
JSON-LD Schema.org (Source Prioritaire)
Backmarket utilise schema.org Product de manière complète et fiable.
Exemple de JSON-LD:
{
"@context": "https://schema.org",
"@type": "Product",
"name": "iPhone 15 Pro",
"image": "https://d2e6ccujb3mkqf.cloudfront.net/...",
"offers": {
"@type": "Offer",
"price": "571.00",
"priceCurrency": "EUR",
"availability": "https://schema.org/InStock"
}
}
Avantages:
- ✅ Données structurées et stables
- ✅ Prix toujours au format numérique propre
- ✅ Devise explicite
- ✅ URL d'image de haute qualité
Extraction prioritaire dans BackmarketStore._extract_json_ld():
def _extract_json_ld(self, soup: BeautifulSoup) -> dict:
"""Extrait les données depuis JSON-LD schema.org."""
json_ld_scripts = soup.find_all("script", {"type": "application/ld+json"})
for script in json_ld_scripts:
data = json.loads(script.string)
if data.get("@type") == "Product":
return {
"name": data.get("name"),
"price": float(data["offers"]["price"]),
"priceCurrency": data["offers"]["priceCurrency"],
"images": [data.get("image")]
}
Sélecteurs CSS (Fallback)
Si JSON-LD n'est pas disponible, on utilise des sélecteurs CSS relativement stables.
Sélecteurs identifiés:
| Champ | Sélecteur | Stabilité |
|---|---|---|
| Titre | h1.heading-1 |
⭐⭐⭐⭐ Stable |
| Prix | div[data-test='price'] |
⭐⭐⭐⭐ Stable |
| Condition | button[data-test='condition-button'] |
⭐⭐⭐⭐ Stable |
| Images | img[alt] |
⭐⭐⭐ Moyen (filtrer par nom produit) |
| Stock | button[data-test='add-to-cart'] |
⭐⭐⭐⭐ Stable |
| Specs | dl > dt, dd |
⭐⭐⭐ Moyen |
| Category | nav[aria-label='breadcrumb'] a |
⭐⭐⭐ Moyen |
Stabilité des sélecteurs: Bonne - Backmarket utilise des classes sémantiques (heading-1) et des attributs data-test qui sont plus stables que les classes générées aléatoirement.
🔧 Implémentation Technique
URL Pattern & SKU Extraction
Format URL: https://www.backmarket.fr/{locale}/p/{slug}
Exemples:
https://www.backmarket.fr/fr-fr/p/iphone-15-pro→ SKU ="iphone-15-pro"https://www.backmarket.com/en-us/p/macbook-air-m2→ SKU ="macbook-air-m2"
Regex d'extraction:
def extract_reference(self, url: str) -> Optional[str]:
match = re.search(r"/p/([a-z0-9-]+)", url, re.IGNORECASE)
if match:
return match.group(1)
return None
Caractéristiques du slug:
- Format kebab-case:
product-name-variant - Peut contenir chiffres:
iphone-15-pro,galaxy-s23 - Stable dans le temps (identifiant produit)
Canonicalization
On retire les paramètres de query et le fragment car ils ne changent pas le produit.
def canonicalize(self, url: str) -> str:
parsed = urlparse(url)
return f"{parsed.scheme}://{parsed.netloc}{parsed.path}"
Exemples:
https://www.backmarket.fr/fr-fr/p/iphone-15-pro?color=black→https://www.backmarket.fr/fr-fr/p/iphone-15-prohttps://www.backmarket.fr/fr-fr/p/iphone-15-pro#specs→https://www.backmarket.fr/fr-fr/p/iphone-15-pro
📈 Tests & Validation
Test Coverage
Tests unitaires: 19 tests Tests fixtures: 11 tests Total: 30 tests - 100% PASS ✅
Coverage du store: 85%
Fichiers de tests:
tests/stores/test_backmarket.py- Tests unitaires (match, canonicalize, extract_reference, parse)tests/stores/test_backmarket_fixtures.py- Tests avec HTML réel
Fixture Réelle
Produit: iPhone 15 Pro (reconditionné)
Fichier: pricewatch/app/stores/backmarket/fixtures/backmarket_iphone15pro.html
Taille: 1.5 MB
Date capture: 2026-01-13
Méthode: Playwright (obligatoire)
Données extraites de la fixture:
{
"source": "backmarket",
"title": "iPhone 15 Pro",
"price": 571.0,
"currency": "EUR",
"reference": "iphone-15-pro",
"images": ["https://d2e6ccujb3mkqf.cloudfront.net/..."],
"is_complete": true
}
⚖️ Comparaison avec Autres Stores
| Aspect | Amazon | Cdiscount | Backmarket |
|---|---|---|---|
| Anti-bot | Faible | Fort (Baleen) | Fort (Cloudflare) |
| Méthode | HTTP OK | Playwright | Playwright |
| JSON-LD | Partiel | ✗ Non | ✓ Oui (complet) |
| Sélecteurs | Stables (IDs) | Instables | Stables (data-test) |
| SKU format | /dp/{ASIN} |
/f-{cat}-{SKU} |
/p/{slug} |
| Parsing fiabilité | ⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
| Vitesse fetch | Rapide (200ms) | Lent (2-3s) | Lent (2-3s) |
| Particularité | - | Prix dynamiques | Reconditionné |
Conclusion: Backmarket est le store le plus fiable pour le parsing grâce au JSON-LD, mais nécessite Playwright comme Cdiscount.
✅ Avantages de Backmarket
- JSON-LD schema.org complet → Parsing ultra-fiable
- Classes CSS stables → Moins de casse que Cdiscount
- URL propre et prévisible → SKU facile à extraire
- Format prix standardisé → Toujours numérique dans JSON-LD
- Sélecteurs
data-test→ Conçus pour être stables
❌ Inconvénients & Défis
1. Protection Anti-bot Obligatoire
Impact:
- ⏱️ Temps de fetch: ~2-3 secondes (vs 200ms pour HTTP)
- 💰 Coût: Plus de ressources CPU/mémoire
- 🐳 Docker: Nécessite installation de Playwright browsers
Solution: Utiliser le cache agressivement, éviter les fetch répétés.
2. Prix Variable selon Condition
Le même produit peut avoir 5-10 prix différents selon l'état.
Problème: Quel prix extraire ? Solution actuelle: On extrait le prix de l'offre par défaut sélectionnée (souvent "Excellent")
Amélioration future: Extraire toutes les offres avec leurs conditions et prix.
3. Stock Complexe
Le stock dépend de l'offre ET de la condition choisie.
Problème: Un produit peut être "en stock" dans une condition mais "rupture" dans une autre. Solution actuelle: On extrait le stock de l'offre par défaut.
4. 404 Fréquents
Les produits reconditionnés ont un stock limité et les URLs peuvent devenir invalides rapidement.
Exemple testé:
https://www.backmarket.fr/fr-fr/p/samsung-galaxy-s23→ 404https://www.backmarket.fr/fr-fr/p/apple-macbook-air-133-pouces-m2-2022→ 404
Impact: Plus de gestion d'erreurs nécessaire dans le pipeline.
🎓 Recommandations
Pour le Développement
- Toujours utiliser Playwright pour Backmarket - Ne jamais tenter HTTP
- Prioriser JSON-LD - C'est la source la plus fiable
- Extraire la condition - Ajouter dans
specs["Condition"] - Gérer les 404 gracefully - Produits limités en stock
- Cache long - Minimiser les appels Playwright coûteux
Pour les Tests
- Maintenir les fixtures à jour - Les URLs expirent vite
- Tester avec différentes catégories - Smartphones, laptops, tablets
- Tester les différentes conditions - Prix varie selon état
- Tester les 404 - Cas fréquent pour le reconditionné
Pour la Production
- Monitoring des 404 - Alertes sur produits devenus indisponibles
- Rotation des proxies - Si scraping intensif
- Rate limiting - Respecter le site (2-3s entre requêtes minimum)
- Cache agressif - Playwright coûte cher en ressources
📝 Exemples d'Utilisation
Scraping Simple
from pricewatch.app.scraping.pw_fetch import fetch_playwright
from pricewatch.app.stores.backmarket.store import BackmarketStore
url = "https://www.backmarket.fr/fr-fr/p/iphone-15-pro"
# Fetch avec Playwright (obligatoire)
result = fetch_playwright(url, headless=True, timeout_ms=60000)
# Parse
store = BackmarketStore()
snapshot = store.parse(result.html, url)
print(f"Title: {snapshot.title}")
print(f"Price: {snapshot.price} {snapshot.currency}")
print(f"Condition: {snapshot.specs.get('Condition', 'N/A')}")
print(f"Complete: {snapshot.is_complete()}")
Détection Automatique
from pricewatch.app.core.registry import StoreRegistry
url = "https://www.backmarket.fr/fr-fr/p/iphone-15-pro"
# Détection automatique du store
store = StoreRegistry.detect(url)
print(f"Store détecté: {store.store_id}") # → "backmarket"
print(f"Score: {store.match(url)}") # → 0.9
Pipeline Complet
from pricewatch.app.cli.main import scrape_url
url = "https://www.backmarket.fr/fr-fr/p/iphone-15-pro"
# Pipeline complet: detect → fetch → parse → save
snapshot = scrape_url(
url,
use_playwright=True, # Obligatoire pour Backmarket
save_html=True,
save_screenshot=True
)
print(f"✓ Scraped: {snapshot.title} - {snapshot.price} {snapshot.currency}")
🔍 Points d'Attention pour Debug
Si le parsing échoue:
- Vérifier que Playwright est utilisé - HTTP ne fonctionne jamais
- Vérifier le code status - Peut être 404 si produit épuisé
- Inspecter le JSON-LD - C'est la source prioritaire
- Vérifier la condition - Prix peut varier selon offre sélectionnée
- Logs détaillés - Activer
--debugpour voir les erreurs
Exemple de debug:
# Activer les logs détaillés
export PRICEWATCH_LOG_LEVEL=DEBUG
# Scraper avec sauvegarde HTML
pricewatch fetch https://www.backmarket.fr/fr-fr/p/iphone-15-pro \
--playwright \
--save-html \
--debug
📚 Ressources
Documentation officielle: https://www.backmarket.fr Fichiers du projet:
pricewatch/app/stores/backmarket/store.py- Implémentationpricewatch/app/stores/backmarket/selectors.yml- Sélecteurs CSSpricewatch/app/stores/backmarket/fixtures/README.md- Documentation des fixturestests/stores/test_backmarket.py- Tests unitairestests/stores/test_backmarket_fixtures.py- Tests avec HTML réel
Tests:
# Tous les tests Backmarket
pytest tests/stores/test_backmarket*.py -v
# Avec coverage
pytest tests/stores/test_backmarket*.py --cov=pricewatch.app.stores.backmarket
🎉 Conclusion
Backmarket est un excellent store à supporter pour PriceWatch:
- ✅ Parsing très fiable grâce au JSON-LD
- ✅ Sélecteurs stables (data-test, classes sémantiques)
- ✅ Tests complets (30 tests, 100% pass)
- ⚠️ Nécessite Playwright (coût en performance)
- ⚠️ URLs peuvent expirer (stock limité)
Score final: ⭐⭐⭐⭐⭐ (5/5) pour la fiabilité du parsing.
Recommandation: Store prioritaire à maintenir pour le marché du reconditionné.