Avertissement légal. Le scraping de résultats de recherche Amazon doit respecter les Conditions d'Utilisation d'Amazon, le Computer Fraud and Abuse Act (CFAA) aux États-Unis et le RGPD dans l'UE. Ce guide couvre uniquement la collecte de données de recherche publiques — de préférence sur vos propres listings ou avec un throttling raisonnable. Pour un accès officiel aux données produit, préférez l'Amazon SP-API lorsque c'est possible.
Pourquoi le suivi de classement de mots-clés Amazon avec proxy est spécifique
Amazon n'est pas Google. Le moteur de recherche d'Amazon fonctionne comme un SERP autonome où le classement est déterminé par la pertinence textuelle et la vélocité de ventes (sales velocity), pas par des backlinks. Pour un vendeur ou un développeur SEO marketplace, le suivi de classement de mots-clés Amazon avec proxy est la seule façon de mesurer la position organique d'un ASIN par mot-clé, par marketplace et par jour. Amazon localise les résultats par marché (amazon.com, amazon.de, amazon.co.uk) et applique des mécanismes anti-bot agressifs qui bloquent rapidement les IPs datacenter.
Contrairement à Google SERP, Amazon affiche à la fois des résultats organiques et des placements sponsorisés (Sponsored) dans la même page. Un bon outil de suivi doit distinguer les deux, sinon vos métriques seront polluées par les annonces payantes. De plus, Amazon pagine ses résultats (généralement 10 à 16 produits par page) et limite l'accès aux pages profondes — rarement au-delà de la page 5 à 7.
Anatomie d'une page de résultats Amazon
La page de recherche Amazon est rendue avec des attributs data-component-type sur chaque carte produit. Le sélecteur clé est [data-component-type="s-search-result"], qui contient chaque produit individuel. À l'intérieur de chaque carte :
data-asin— l'identifiant ASIN du produit- Le libellé « Sponsored » ou « Sponsorisé » pour les placements payants
- Le titre, le prix, la note (étoiles) et le nombre d'avis
La position organique se calcule en ignorant les résultats sponsorisés. Par exemple, si le premier résultat est une annonce Sponsored et le deuxième est organique, le deuxième résultat a une position organique de 1, pas 2.
Détecter les placements Sponsorisés
Amazon marque les annonces sponsorisées avec un badge texte. Sur amazon.com, c'est « Sponsored » ; sur amazon.de, c'est « Sponsored » ou « Sponsorisiert ». On peut le détecter en cherchant du texte contenant « Sponsored » ou « Sponsorisé » dans le corps de la carte produit.
Pourquoi les proxies résidentiels sont nécessaires
Amazon applique plusieurs couches de protection :
- Géo-localisation par marketplace : amazon.com renvoie des résultats US par défaut, amazon.de des résultats allemands. Une IP US qui interroge amazon.de peut obtenir des résultats dégradés ou localisés.
- Détection d'IP datacenter : Amazon bloque ou CAPTCHA les requêtes venant de plages d'IP connues comme datacenter (AWS, OVH, DigitalOcean).
- Rate limiting par IP : trop de requêtes depuis la même IP déclenchent des CAPTCHAs ou des blocages temporaires, souvent après seulement 50 à 100 requêtes en peu de temps.
- Empreinte TLS : Amazon vérifie le JA3/JA4 fingerprint du client TLS. Un client Python standard avec
requestsa une empreinte différente d'un vrai navigateur Chrome.
Les proxies résidentiels résolvent les deux premiers problèmes : ils offrent des IPs d'origine FAI (ISP) géolocalisables par pays. Pour la pagination stable (pages 1 à 5 d'un même mot-clé), on utilise des sessions sticky qui maintiennent la même IP sur plusieurs requêtes consécutives.
Géo-ciblage ProxyHat par marketplace
Avec ProxyHat, le géo-ciblage se fait dans le nom d'utilisateur :
user-country-US:passpour amazon.comuser-country-DE:passpour amazon.deuser-country-GB:passpour amazon.co.ukuser-country-FR:passpour amazon.fr
Pour la pagination, on ajoute un identifiant de session : user-country-US-session-abc123:pass. Toutes les requêtes avec le même session-abc123 sortiront par la même IP résidentielle, ce qui est crucial pour ne pas obtenir des résultats incohérents entre les pages. Consultez la liste complète des localisations disponibles sur ProxyHat.
Implémentation Python : scraping SERP Amazon avec curl_cffi
curl_cffi est une bibliothèque Python qui réplique l'empreinte TLS de Chrome, ce qui permet de contourner la détection TLS d'Amazon. Combiné avec les proxies résidentiels ProxyHat, c'est l'approche la plus légère pour un outil de suivi de classement Amazon.
import re
import time
import json
from datetime import datetime
from curl_cffi import requests
from bs4 import BeautifulSoup
# Configuration ProxyHat
PROXY_HTTP = "http://user-country-US:pass@gate.proxyhat.com:8080"
MARKETPLACE = "https://www.amazon.com"
KEYWORD = "wireless earbuds"
TARGET_ASIN = "B0CX22DQFS"
MAX_PAGES = 5
def build_url(keyword: str, page: int) -> str:
"""Construit l'URL de recherche Amazon avec pagination."""
q = keyword.replace(" ", "+")
return f"{MARKETPLACE}/s?k={q}&page={page}"
def fetch_page(url: str, session_id: str) -> str:
"""Fetch une page avec proxy résidentiel et session sticky."""
proxy = f"http://user-country-US-session-{session_id}:pass@gate.proxyhat.com:8080"
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
"Accept-Language": "en-US,en;q=0.9",
"Accept-Encoding": "gzip, deflate, br",
}
resp = requests.get(url, proxy=proxy, headers=headers, impersonate="chrome131", timeout=30)
resp.raise_for_status()
return resp.text
def parse_results(html: str) -> list[dict]:
"""Parse les résultats de recherche Amazon."""
soup = BeautifulSoup(html, "html.parser")
results = []
cards = soup.select('[data-component-type="s-search-result"]')
for card in cards:
asin = card.get("data-asin", "")
if not asin:
continue
sponsored_text = card.get_text(" ", strip=True).lower()
is_sponsored = "sponsored" in sponsored_text or "sponsorisé" in sponsored_text
title_el = card.select_one("h2 a span") or card.select_one("h2 span")
title = title_el.get_text(strip=True) if title_el else ""
results.append({"asin": asin, "title": title, "is_sponsored": is_sponsored})
return results
def find_organic_position(results: list[dict], target_asin: str) -> int | None:
"""Calcule la position organique d'un ASIN (en ignorant les sponsorisés)."""
organic_rank = 0
for r in results:
if r["is_sponsored"]:
continue
organic_rank += 1
if r["asin"] == target_asin:
return organic_rank
return None
# --- Exécution principale ---
session_id = f"track-{int(time.time())}"
all_positions = []
for page in range(1, MAX_PAGES + 1):
url = build_url(KEYWORD, page)
html = fetch_page(url, session_id)
results = parse_results(html)
pos = find_organic_position(results, TARGET_ASIN)
all_positions.append({"page": page, "position": pos, "timestamp": datetime.now().isoformat()})
print(f"Page {page}: ASIN {TARGET_ASIN} → position organique = {pos}")
time.sleep(2) # Throttle entre les pages
# Sauvegarder l'historique
with open("rank_history.json", "a") as f:
for entry in all_positions:
if entry["position"] is not None:
f.write(json.dumps(entry) + "\n")
Version Playwright pour les pages dynamiques
Si Amazon rend certains résultats en JavaScript (ce qui arrive sur les pages de recherche avec carrousels), Playwright avec proxy est plus robuste :
import asyncio
from datetime import datetime
from playwright.async_api import async_playwright
PROXY = {"server": "http://gate.proxyhat.com:8080", "username": "user-country-DE-session-track001", "password": "pass"}
MARKETPLACE = "https://www.amazon.de"
KEYWORD = "bluetooth lautsprecher"
TARGET_ASIN = "B0DCKP3MJ5"
async def track_keyword_rank():
async with async_playwright() as p:
browser = await p.chromium.launch(headless=True, proxy=PROXY)
context = await browser.new_context(
locale="de-DE",
user_agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36",
)
page = await context.new_page()
organic_rank = 0
for pg in range(1, 6):
url = f"{MARKETPLACE}/s?k={KEYWORD.replace(' ', '+')}&page={pg}"
await page.goto(url, wait_until="domcontentloaded", timeout=30000)
await page.wait_for_selector('[data-component-type="s-search-result"]', timeout=10000)
cards = await page.query_selector_all('[data-component-type="s-search-result"]')
for card in cards:
asin = await card.get_attribute("data-asin")
if not asin:
continue
text = await card.inner_text()
is_sponsored = "Sponsored" in text or "Sponsorisiert" in text
if is_sponsored:
continue
organic_rank += 1
if asin == TARGET_ASIN:
print(f"Trouvé à la position organique {organic_rank} (page {pg})")
await browser.close()
return organic_rank
await asyncio.sleep(2)
print(f"ASIN {TARGET_ASIN} non trouvé dans les 5 premières pages")
await browser.close()
return None
asyncio.run(track_keyword_rank())
Version curl en ligne de commande
Pour un test rapide ou un script shell, voici comment interroger Amazon via un proxy résidentiel ProxyHat :
# Recherche Amazon US via proxy résidentiel ProxyHat
curl -x http://user-country-US-session-test1:pass@gate.proxyhat.com:8080 \
-H "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36" \
-H "Accept-Language: en-US,en;q=0.9" \
--compressed \
"https://www.amazon.com/s?k=wireless+earbuds&page=1" \
-o amazon_page1.html
# Vérifier la présence d'un ASIN dans le HTML
grep -o 'data-asin="B0CX22DQFS"' amazon_page1.html | head -1
Node.js avec fetch et proxy
Pour les équipes JavaScript/TypeScript, voici une implémentation équivalente avec Cheerio :
import { HttpsProxyAgent } from "https-proxy-agent";
import * as cheerio from "cheerio";
const PROXY_URL = "http://user-country-US-session-node01:pass@gate.proxyhat.com:8080";
const MARKETPLACE = "https://www.amazon.com";
const KEYWORD = "mechanical keyboard";
const TARGET_ASIN = "B0CM5JQ9ZQ";
const agent = new HttpsProxyAgent(PROXY_URL);
async function fetchPage(url) {
const resp = await fetch(url, {
agent,
headers: {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36",
"Accept-Language": "en-US,en;q=0.9",
},
});
if (!resp.ok) throw new Error(`HTTP ${resp.status}`);
return await resp.text();
}
function parseResults(html) {
const $ = cheerio.load(html);
const results = [];
$('[data-component-type="s-search-result"]').each((i, el) => {
const asin = $(el).attr("data-asin");
if (!asin) return;
const text = $(el).text().toLowerCase();
const isSponsored = text.includes("sponsored");
const title = $(el).find("h2 span").first().text().trim();
results.push({ asin, title, isSponsored });
});
return results;
}
async function trackRank() {
let organicRank = 0;
for (let page = 1; page <= 5; page++) {
const url = `${MARKETPLACE}/s?k=${encodeURIComponent(KEYWORD)}&page=${page}`;
const html = await fetchPage(url);
const results = parseResults(html);
for (const r of results) {
if (r.isSponsored) continue;
organicRank++;
if (r.asin === TARGET_ASIN) {
console.log(`Position organique: ${organicRank} (page ${page})`);
return { page, organicRank };
}
}
await new Promise((r) => setTimeout(r, 2000));
}
console.log("ASIN non trouvé dans les 5 pages");
return null;
}
trackRank().catch(console.error);
Production : planification, retries et détection CAPTCHA
Un outil de suivi de classement Amazon en production nécessite plusieurs couches de robustesse. Voici les patterns essentiels.
Planification quotidienne avec APScheduler
Un suivi quotidien suffit pour la plupart des cas. Amazon ne met pas à jour le classement en temps réel — une fréquence de 24h est standard dans l'industrie.
from apscheduler.schedulers.asyncio import AsyncIOScheduler
import asyncio, logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger("amazon-tracker")
async def daily_track():
"""Job quotidien : suivre N mots-clés pour M ASINs."""
keywords = ["wireless earbuds", "bluetooth speaker", "usb-c cable"]
asins = ["B0CX22DQFS", "B0DCKP3MJ5", "B0CM5JQ9ZQ"]
for kw in keywords:
for asin in asins:
try:
pos = await track_single(kw, asin)
logger.info(f"{kw} / {asin} → pos {pos}")
except Exception as e:
logger.error(f"Erreur pour {kw}/{asin}: {e}")
await asyncio.sleep(3) # Throttle entre les requêtes
scheduler = AsyncIOScheduler()
scheduler.add_job(daily_track, "interval", hours=24, max_instances=1)
scheduler.start()
asyncio.get_event_loop().run_forever()
Retries avec backoff exponentiel
Quand Amazon renvoie un 429 ou un CAPTCHA, il faut réessayer avec un backoff exponentiel et idéalement une nouvelle session proxy :
import asyncio
from tenacity import retry, stop_after_attempt, wait_exponential, retry_if_exception_type
class CaptchaDetected(Exception):
"""Levé quand Amazon renvoie un CAPTCHA."""
pass
class RateLimited(Exception):
"""Levé quand Amazon renvoie 429 ou 503."""
pass
@retry(
stop=stop_after_attempt(5),
wait=wait_exponential(multiplier=2, min=4, max=60),
retry=retry_if_exception_type((RateLimited, CaptchaDetected)),
)
async def fetch_with_retry(url: str, session_id: str) -> str:
proxy = f"http://user-country-US-session-{session_id}:pass@gate.proxyhat.com:8080"
async with httpx.AsyncClient(proxy=proxy, timeout=30) as client:
resp = await client.get(url, headers={"User-Agent": "Mozilla/5.0 ..."})
if resp.status_code in (429, 503):
raise RateLimited(f"HTTP {resp.status_code}")
html = resp.text
if "api-services-support@amazon.com" in html or "Type the characters you see in this image" in html:
raise CaptchaDetected("CAPTCHA détecté sur la page")
return html
Détection de CAPTCHA
Amazon renvoie des CAPTCHAs quand il détecte un comportement automatisé. Les signaux à surveiller dans le HTML :
- Présence de
api-services-support@amazon.com - Texte « Type the characters you see in this image »
- Code HTTP 429 (Too Many Requests) ou 503 ( Service Unavailable)
- Redirection vers
/errors/validateCaptcha
Quand un CAPTCHA est détecté, la stratégie recommandée est de changer de session proxy (nouvel identifiant de session = nouvelle IP) et de réessayer après un délai. Ne tentez jamais de résoudre le CAPTCHA automatiquement — c'est contre les conditions d'utilisation d'Amazon.
Vérification d'indexation
Avant de suivre le classement, vérifiez que l'ASIN est indexé pour ce mot-clé. Si find_organic_position retourne None sur les 5 premières pages, l'ASIN n'est pas indexé pour ce terme — c'est un signal SEO Amazon important. Un ASIN peut être indexé mais classé au-delà de la page 5 (position 50+), ce qui indique un problème de pertinence.
Comparaison : curl_cffi vs Playwright vs SP-API
| Méthode | Empreinte TLS | Latence typique | Coût | Couverture |
|---|---|---|---|---|
| curl_cffi + proxy résidentiel | Chrome 131 (réel) | ~200ms par page | Proxies uniquement | HTML statique, 95% des cas |
| Playwright + proxy résidentiel | Chrome réel (headless) | ~800ms par page | Proxies + CPU | Pages JS dynamiques, 100% |
| Amazon SP-API | N/A (API officielle) | ~150ms par appel | Gratuit (quota) | Données produit, pas de SERP |
L'SP-API ne fournit pas de données de classement de recherche (SERP). Elle donne accès aux métriques vendeur (impressions, clics, conversions via Reports API), mais pas à la position organique d'un ASIN pour un mot-clé donné. Le scraping reste donc nécessaire pour le suivi de classement. Pour en savoir plus sur les bonnes pratiques de scraping, consultez notre guide sur le web scraping avec proxies et le suivi de SERP.
Bonnes pratiques et éthique
- Suivez vos propres listings ou des données de recherche publiquement accessibles. Le scraping de données concurrentielles à grande échelle peut violer les conditions d'utilisation d'Amazon.
- Throttlez vos requêtes : 2 à 5 secondes entre chaque page, 3 à 5 secondes entre chaque mot-clé. Une cadence agressive déclenche des blocages.
- Utilisez le bon pays : interroger amazon.com avec une IP allemande donne des résultats faussés. Le géo-ciblage ProxyHat
-country-USpour amazon.com,-country-DEpour amazon.de, etc. - Préférez l'SP-API pour les données produit officielles (stock, prix, Buy Box). Le scraping SERP est pour le classement uniquement.
- Respectez robots.txt : vérifiez
https://www.amazon.com/robots.txtrégulièrement pour les règles de crawl. - Conformité RGPD/CCPA : les données de recherche Amazon ne contiennent pas de données personnelles, mais le logging d'IPs proxy dans vos logs doit être conforme au RGPD.
Points clés à retenir
Le suivi de classement de mots-clés Amazon avec proxy nécessite trois éléments : un client HTTP avec empreinte TLS réaliste (curl_cffi ou Playwright), un proxy résidentiel géo-ciblé (ProxyHat
-country-XX), et une logique de parsing qui sépare les résultats organiques des sponsorisés. Avec des sessions sticky pour la pagination, un throttling de 2 à 5 secondes et une détection CAPTCHA, vous obtenez un outil fiable pour suivre quotidiennement la position de vos ASINs sur n'importe quelle marketplace Amazon.
Prêt à commencer ? Consultez la tarification ProxyHat pour choisir le plan de proxies résidentiels adapté à votre volume de suivi, ou explorez la documentation ProxyHat pour les options avancées de géo-ciblage et de rotation.





