Nota legale: Questo articolo tratta esclusivamente la raccolta di dati di ricerca pubblicamente accessibili. Negli Stati Uniti, il Computer Fraud and Abuse Act (CFAA) disciplina l'accesso non autorizzato a sistemi informatici; negli Stati Uniti, consulta anche le linee guida della FTC. Nell'UE, il GDPR impone limiti sul trattamento di dati personali. Non accedere a dati protetti, non aggirare misure di sicurezza, e rispetta i Termini di Servizio di Amazon.
Perché il Tracciamento Ranking Keyword Amazon con Proxy è Diverso
Amazon non è un motore di ricerca generico. Il suo algoritmo di ranking — noto come A9 — combina segnali di rilevanza testuale con metriche di performance commerciale: sales velocity, tasso di conversione, recensioni, e disponibilità. Questo significa che la stessa keyword può posizionare un ASIN in modo completamente diverso rispetto a Google, e le posizioni cambiano frequentemente, anche più volte al giorno.
Per i seller e i team SEO di marketplace, il tracciamento ranking keyword Amazon con proxy è essenziale per monitorare la posizione organica di un ASIN per keyword specifiche, in un marketplace specifico (amazon.com, amazon.de, amazon.co.uk), nel tempo. Senza proxy residenziali geolocalizzati, i tentativi di scraping vengono bloccati rapidamente: Amazon applica rate limiting aggressivo, CAPTCHA, e localizzazione basata sull'IP che distorce i risultati.
Il problema della localizzazione per marketplace
Amazon serve risultati diversi in base all'IP del visitatore. Se richiedi una pagina di ricerca da un IP italiano verso amazon.de, potresti ottenere risultati filtrati, prezzi in EUR ma con logistica diversa, o un redirect. Per un tracciamento accurato serve un IP residenziale nel paese del marketplace target.
Anatomia della SERP di Amazon: Cosa Parsingare
La pagina dei risultati di ricerca di Amazon ha una struttura DOM relativamente stabile. Ogni risultato organico è contenuto in un elemento con data-component-type="s-search-result". Ecco i campi chiave da estrarre:
data-asin— l'identificativo univoco del prodotto (10 caratteri).- Posizione organica — l'indice del risultato nella lista, contando solo i risultati organici (escludendo i placement Sponsored).
- Placement Sponsored — identificato dal label "Sponsored" nel markup, di solito in un tag
spanoacon testo "Sponsored" o un attributo aria-label. - Titolo, prezzo, rating, numero di recensioni — per arricchire il dataset.
La distinzione tra organico e Sponsored è cruciale: un ASIN può apparire in posizione 1 come annuncio pagato ma essere in posizione 15 organicamente. Confondere i due distorce completamente le metriche di ranking.
Perché i Proxy Residenziali sono Necessari
Amazon implementa multiple difese anti-bot:
- Rate limiting per IP — poche decine di richieste consecutive dallo stesso IP attivano CAPTCHA o blocchi temporanei.
- Localizzazione geografica — l'IP determina il marketplace "di default" e filtra i risultati.
- Fingerprinting TLS/HTTP — Amazon rileva client HTTP con fingerprint non browser (es. richieste Python urllib standard).
- Rotazione contenuti — layout A/B test che cambiano selettori CSS nel tempo.
I proxy residenziali risolvono i primi due problemi: forniscono IP di dispositivi reali nel paese target, rendendo ogni richiesta indistinguibile dal traffico di un consumatore legittimo. La geolocalizzazione per paese è fondamentale: per amazon.com serve IP US, per amazon.de serve IP DE, per amazon.co.uk serve IP GB.
Le sessioni sticky mantengono lo stesso IP per richieste correlate — necessario quando si paginano i risultati (pagine 1-5) per evitare che Amazon serva risultati inconsistenti tra una pagina e l'altra.
Confronto: Tipi di Proxy per Amazon SERP Scraping
| Tipo Proxy | Success Rate stimato | Localizzazione | Costo relativo | Idoneo per Amazon |
|---|---|---|---|---|
| Datacenter | 20-40% | Possibile ma facilmente flaggato | Basso | No |
| Mobile | 85-95% | Ottima (IP SIM reali) | Alto | Sì, per alto volume |
| Residenziale | 90-98% | Paese e città | Medio | Sì, consigliato |
Setup ProxyHat: Geolocalizzazione e Sessioni Sticky
ProxyHat supporta geolocalizzazione per paese e città direttamente nel username, e sessioni sticky tramite il flag -session-. Ecco i formati:
# HTTP proxy per amazon.com (IP US)
http://user-country-US:pass@gate.proxyhat.com:8080
# HTTP proxy per amazon.de (IP DE)
http://user-country-DE:pass@gate.proxyhat.com:8080
# HTTP proxy per amazon.co.uk (IP GB) con sessione sticky
http://user-country-GB-session-mykw123:pass@gate.proxyhat.com:8080
# SOCKS5 proxy
socks5://user-country-US:pass@gate.proxyhat.com:1080
La sessione sticky garantisce che tutte le richieste con session-mykw123 escano dallo stesso IP residenziale per la durata della sessione (tipicamente 10-30 minuti). Questo è essenziale per la paginazione coerente.
Esempio 1: curl_cffi con Proxy Residenziali
curl_cffi è una libreria Python che usa il motore TLS di curl con fingerprint browser reali, bypassando il fingerprinting TLS che blocca requests standard. È la scelta più leggera per Amazon SERP scraping.
import re
import json
import time
from curl_cffi import requests as cffi_requests
from datetime import datetime, timezone
# Configurazione ProxyHat per amazon.com
PROXY_URL = "http://user-country-US:pass@gate.proxyhat.com:8080"
MARKETPLACES = {
"US": "https://www.amazon.com",
"DE": "https://www.amazon.de",
"GB": "https://www.amazon.co.uk",
}
def build_proxy(country: str, session_id: str | None = None) -> dict:
"""Costruisce l'URL proxy ProxyHat con geolocalizzazione e sessione opzionale."""
user = f"user-country-{country}"
if session_id:
user += f"-session-{session_id}"
return {"http": f"http://{user}:pass@gate.proxyhat.com:8080",
"https": f"http://{user}:pass@gate.proxyhat.com:8080"}
def fetch_search_page(keyword: str, page: int, country: str = "US",
session_id: str | None = None) -> str:
"""Scarica una pagina di ricerca Amazon con proxy residenziale geolocalizzato."""
base = MARKETPLACES[country]
url = f"{base}/s?k={keyword}&page={page}"
proxies = build_proxy(country, session_id)
headers = {
"accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
"accept-language": "en-US,en;q=0.9" if country == "US" else "de-DE,de;q=0.9",
"sec-fetch-dest": "document",
"sec-fetch-mode": "navigate",
"sec-fetch-site": "none",
"upgrade-insecure-requests": "1",
}
resp = cffi_requests.get(url, proxies=proxies, headers=headers,
impersonate="chrome120", timeout=30)
if resp.status_code == 503:
raise RuntimeError("CAPTCHA o blocco anti-bot rilevato (503)")
if resp.status_code != 200:
raise RuntimeError(f"HTTP {resp.status_code}")
return resp.text
Esempio 2: Parsing della SERP con Estrazione Posizione Organica
from html.parser import HTMLParser
import re
class AmazonSERPParser(HTMLParser):
"""Parser minimale per la SERP di Amazon — estrae ASIN, posizione organica, Sponsored."""
def __init__(self):
super().__init__()
self.results = []
self._current_asin = None
self._current_is_sponsored = False
self._in_sponsored_label = False
self._depth = 0
def handle_starttag(self, tag, attrs):
attrs_dict = dict(attrs)
if attrs_dict.get("data-component-type") == "s-search-result":
self._current_asin = attrs_dict.get("data-asin")
self._current_is_sponsored = False
# Rilevazione label "Sponsored"
if tag == "span" and "a-color-secondary" in attrs_dict.get("class", ""):
self._in_sponsored_label = True
def handle_endtag(self, tag):
if tag == "div" and self._current_asin:
self._depth -= 1
if self._depth <= 0:
self.results.append({
"asin": self._current_asin,
"is_sponsored": self._current_is_sponsored,
})
self._current_asin = None
self._current_is_sponsored = False
self._depth = 0
def handle_data(self, data):
if self._in_sponsored_label and "Sponsored" in data:
self._current_is_sponsored = True
self._in_sponsored_label = False
def parse_amazon_serp(html: str) -> list[dict]:
"""Estrae i risultati dalla SERP, calcolando la posizione organica."""
parser = AmazonSERPParser()
parser.feed(html)
organic_position = 0
for i, result in enumerate(parser.results):
if not result["is_sponsored"]:
organic_position += 1
result["organic_position"] = organic_position
else:
result["organic_position"] = None
result["raw_position"] = i + 1
return parser.results
def find_asin_position(results: list[dict], target_asin: str) -> dict | None:
"""Trova la posizione organica di un ASIN target nei risultati."""
for r in results:
if r["asin"] == target_asin:
return {
"asin": target_asin,
"organic_position": r["organic_position"],
"is_sponsored": r["is_sponsored"],
"raw_position": r["raw_position"],
}
return None
Esempio 3: Tracciamento Multi-Pagina con Sessione Sticky
import time
import json
from datetime import datetime, timezone
def track_keyword(keyword: str, target_asin: str, country: str = "US",
max_pages: int = 5) -> dict:
"""Traccia la posizione organica di un ASIN per una keyword su più pagine.
Usa una sessione sticky ProxyHat per garantire IP coerente durante la paginazione.
"""
session_id = f"kw{int(time.time()) % 100000}"
position_history = []
found = False
for page in range(1, max_pages + 1):
try:
html = fetch_search_page(keyword, page, country, session_id)
results = parse_amazon_serp(html)
if not results:
print(f" Pagina {page}: nessun risultato — possibile CAPTCHA")
break
pos = find_asin_position(results, target_asin)
if pos:
position_history.append({
"page": page,
"organic_position": pos["organic_position"],
"is_sponsored": pos["is_sponsored"],
"timestamp": datetime.now(timezone.utc).isoformat(),
})
if pos["organic_position"]:
found = True
print(f" Pagina {page}: ASIN in posizione organica {pos['organic_position']}")
break
# Throttle: 2-3 secondi tra pagine
time.sleep(2.5)
except RuntimeError as e:
print(f" Pagina {page}: errore — {e}")
# Backoff esponenziale
time.sleep(5 * page)
continue
return {
"keyword": keyword,
"target_asin": target_asin,
"country": country,
"found_organic": found,
"position_history": position_history,
"tracked_at": datetime.now(timezone.utc).isoformat(),
}
# Esecuzione
result = track_keyword("wireless earbuds", "B0CX23V2ZK", country="US", max_pages=5)
print(json.dumps(result, indent=2, ensure_ascii=False))
Esempio 4: Playwright con Proxy per Rendering JavaScript
Quando Amazon serve contenuti via JavaScript (lazy loading, dynamic Sponsored), curl_cffi potrebbe non essere sufficiente. Playwright con proxy residenziale è la soluzione robusta.
import asyncio
from playwright.async_api import async_playwright
from datetime import datetime, timezone
async def track_with_playwright(keyword: str, target_asin: str,
country: str = "US") -> dict:
"""Usa Playwright con proxy ProxyHat per rendering completo della SERP."""
proxy_config = {
"server": "http://gate.proxyhat.com:8080",
"username": f"user-country-{country}",
"password": "pass",
}
async with async_playwright() as p:
browser = await p.chromium.launch(
headless=True,
proxy=proxy_config,
args=["--disable-blink-features=AutomationControlled"],
)
context = await browser.new_context(
locale="en-US" if country == "US" else "de-DE",
user_agent=("Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
"AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/120.0.0.0 Safari/537.36"),
viewport={"width": 1920, "height": 1080},
)
page = await context.new_page()
url = f"https://www.amazon.com/s?k={keyword}"
if country == "DE":
url = f"https://www.amazon.de/s?k={keyword}"
await page.goto(url, wait_until="domcontentloaded", timeout=30000)
await page.wait_for_selector('[data-component-type="s-search-result"]', timeout=15000)
# Estrazione via DOM
results = await page.evaluate("""() => {
const items = document.querySelectorAll('[data-component-type="s-search-result"]');
const data = [];
let organicPos = 0;
items.forEach((item, idx) => {
const asin = item.getAttribute('data-asin');
const sponsoredLabel = item.querySelector('span.a-color-secondary');
const isSponsored = sponsoredLabel && sponsoredLabel.textContent.includes('Sponsored');
if (!isSponsored) organicPos++;
data.push({
asin: asin,
raw_position: idx + 1,
organic_position: isSponsored ? null : organicPos,
is_sponsored: isSponsored,
});
});
return data;
}""")
await browser.close()
target = next((r for r in results if r["asin"] == target_asin), None)
return {
"keyword": keyword,
"target_asin": target_asin,
"country": country,
"found": target is not None,
"organic_position": target["organic_position"] if target else None,
"is_sponsored": target["is_sponsored"] if target else False,
"tracked_at": datetime.now(timezone.utc).isoformat(),
}
# Esecuzione
result = asyncio.run(track_with_playwright("wireless earbuds", "B0CX23V2ZK", "US"))
print(result)
Esempio 5: Scheduler di Produzione con Retry e Backoff
import logging
import time
import json
from pathlib import Path
from datetime import datetime, timezone
logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s")
logger = logging.getLogger("amazon_tracker")
class AmazonRankTracker:
"""Tracker di produzione con retry, backoff, e persistenza su file JSON."""
def __init__(self, keywords: list[str], target_asins: list[str],
country: str = "US", output_file: str = "rank_history.jsonl"):
self.keywords = keywords
self.target_asins = target_asins
self.country = country
self.output_file = Path(output_file)
self.max_retries = 3
def _backoff_delay(self, attempt: int) -> float:
"""Backoff esponenziale con jitter: 2^attempt + random."""
import random
return (2 ** attempt) + random.uniform(0, 1)
def _is_captcha(self, html: str) -> bool:
"""Rileva CAPTCHA nella risposta HTML."""
captcha_signals = [
"Type the characters you see in this image",
"api-services-support@amazon.com",
"robot check",
"captcha",
]
html_lower = html.lower()
return any(sig.lower() in html_lower for sig in captcha_signals)
def _save_record(self, record: dict):
"""Append record come JSONL per append-only safe."""
with self.output_file.open("a", encoding="utf-8") as f:
f.write(json.dumps(record, ensure_ascii=False) + "\n")
def track_single(self, keyword: str, asin: str) -> dict:
"""Traccia una singola keyword-ASIN con retry e backoff."""
for attempt in range(1, self.max_retries + 1):
try:
session_id = f"{keyword[:5]}{int(time.time()) % 100000}"
html = fetch_search_page(keyword, 1, self.country, session_id)
if self._is_captcha(html):
logger.warning(f"CAPTCHA rilevato per '{keyword}' — tentativo {attempt}")
if attempt < self.max_retries:
delay = self._backoff_delay(attempt)
logger.info(f"Backoff {delay:.1f}s")
time.sleep(delay)
continue
return {"keyword": keyword, "asin": asin, "error": "CAPTCHA",
"tracked_at": datetime.now(timezone.utc).isoformat()}
results = parse_amazon_serp(html)
pos = find_asin_position(results, asin)
record = {
"keyword": keyword,
"asin": asin,
"country": self.country,
"found": pos is not None,
"organic_position": pos["organic_position"] if pos else None,
"is_sponsored": pos["is_sponsored"] if pos else False,
"tracked_at": datetime.now(timezone.utc).isoformat(),
}
self._save_record(record)
logger.info(f"{keyword} / {asin}: pos={record['organic_position']}")
return record
except Exception as e:
logger.error(f"Errore tentativo {attempt}: {e}")
if attempt < self.max_retries:
time.sleep(self._backoff_delay(attempt))
else:
return {"keyword": keyword, "asin": asin, "error": str(e),
"tracked_at": datetime.now(timezone.utc).isoformat()}
return {}
def run_daily(self):
"""Esegue il tracciamento per tutte le keyword/ASIN con throttle."""
logger.info(f"Avvio tracciamento: {len(self.keywords)} keyword, {len(self.target_asins)} ASIN")
for kw in self.keywords:
for asin in self.target_asins:
self.track_single(kw, asin)
# Throttle: 3-5 secondi tra richieste per ridurre risk di blocco
time.sleep(4)
logger.info("Tracciamento completato")
# Utilizzo
tracker = AmazonRankTracker(
keywords=["wireless earbuds", "bluetooth headphones", "noise cancelling earbuds"],
target_asins=["B0CX23V2ZK"],
country="US",
)
tracker.run_daily()
Production Tips: Andare Oltre il MVP
Scheduling giornaliero
Usa cron (Linux) o Task Scheduler (Windows) per eseguire il tracker una o due volte al giorno. Il ranking organico su Amazon cambia con frequenza giornaliera, non oraria — tracciare ogni ora è spesso overkill e aumenta il rischio di blocchi.
# Crontab: esecuzione giornaliera alle 9:00 UTC
0 9 * * * /usr/bin/python3 /opt/amazon_tracker/tracker.py >> /var/log/amazon_tracker.log 2>&1
Circuit breaker per CAPTCHA persistenti
Se più di 3 CAPTCHA consecutivi vengono rilevati, sospendi il tracker per 30-60 minuti. Continuare a bombardare Amazon dopo un blocco garantisce ban dell'IP. Un circuit breaker semplice:
class CircuitBreaker:
def __init__(self, threshold: int = 3, cooldown: int = 1800):
self.failures = 0
self.threshold = threshold
self.cooldown = cooldown
self.opened_at = None
def can_proceed(self) -> bool:
if self.opened_at:
elapsed = time.time() - self.opened_at
if elapsed < self.cooldown:
return False
self.opened_at = None
self.failures = 0
return True
def record_failure(self):
self.failures += 1
if self.failures >= self.threshold:
self.opened_at = time.time()
logger.warning(f"Circuit breaker aperto per {self.cooldown}s")
Indexation check
Prima di tracciare il ranking, verifica che l'ASIN sia indicizzato per quella keyword. Cerca l'ASIN nelle prime 5-10 pagine: se non appare nemmeno come Sponsored, il prodotto potrebbe non essere indicizzato per quella keyword, o potrebbe essere out of stock. Questo è un problema di listing, non di ranking.
Rotazione user-agent e headers
Anche con proxy residenziali, varia il User-Agent tra richieste per ridurre il fingerprinting. Mantieni una pool di 10-20 UA browser reali e ruota casualmente.
Considerazioni Etiche e Alternative
Il tracciamento ranking keyword Amazon con proxy deve essere fatto in modo responsabile:
- Traccia i tuoi ASIN — il caso d'uso più legittimo è monitorare le proprie listing.
- Rispetta i limiti di rate — throttle a 3-5 secondi tra richieste, non superare 1000 richieste/ora per keyword.
- Considera Amazon SP-API — il Selling Partner API di Amazon offre endpoint ufficiali per product catalog e pricing, anche se non fornisce direttamente ranking organico per keyword. Per dati di ranking, lo scraping rimane l'unica via.
- Conformità GDPR — se raccogli dati di recensioni o profili seller, assicurati di non memorizzare dati personali identificabili senza base giuridica.
Per maggiori dettagli sull'infrastruttura proxy, consulta la documentazione ProxyHat, o esplora i casi d'uso di web scraping e il tracciamento SERP. Verifica anche i piani ProxyHat e le locazioni disponibili per il geotargeting.
Punti Chiave
- Amazon è una SERP a sé — il ranking è guidato da sales velocity e rilevanza, non solo da segnali SEO tradizionali.
- Proxy residenziali geolocalizzati sono obbligatori — senza IP nel paese del marketplace, i risultati sono distorti o bloccati.
- Sessioni sticky per paginazione — usa
-session-in ProxyHat per mantenere IP coerente tra pagine 1-5.- Separa organico da Sponsored — confondere i due invalida le metriche di ranking.
- curl_cffi per efficienza, Playwright per robustezza — scegli in base alla complessità della pagina target.
- Circuit breaker e backoff — implementa retry con backoff esponenziale e sospendi dopo CAPTCHA consecutivi.
- Considera SP-API dove possibile — per dati catalog e pricing, l'API ufficiale è più stabile del scraping.
FAQ
Cos'è il tracciamento ranking keyword Amazon con proxy?
È la pratica di monitorare la posizione organica di un ASIN nei risultati di ricerca di Amazon per keyword specifiche, utilizzando proxy residenziali geolocalizzati per evitare blocchi anti-bot e garantire risultati coerenti per marketplace. Permette ai seller di verificare se e dove i loro prodotti appaiono per le keyword target, nel tempo.
Perché il tracciamento ranking keyword Amazon con proxy è importante per gli utenti di proxy?
Amazon applica localizzazione basata su IP e difese anti-bot aggressive. Senza proxy residenziali nel paese del marketplace target, i risultati sono distorti o le richieste vengono bloccate con CAPTCHA (HTTP 503). I proxy residenziali con geolocalizzazione per paese sono l'unico modo affidabile per ottenere dati di ranking accurati e ripetibili.
Quale tipo di proxy funziona meglio per il tracciamento ranking keyword Amazon?
I proxy residenziali sono la scelta consigliata: offrono IP di dispositivi reali geolocalizzati, con un success rate stimato del 90-98%. I proxy datacenter vengono facilmente flaggati (20-40% di successo). I proxy mobile hanno performance simili ai residenziali ma costano di più. Per ProxyHat, usa user-country-US per amazon.com, user-country-DE per amazon.de, con sessioni sticky per la paginazione.
Come evitare i blocchi quando si implementa il tracciamento ranking keyword Amazon con proxy?
Implementa throttle di 3-5 secondi tra richieste, usa sessioni sticky ProxyHat per la paginazione, ruota user-agent, rileva CAPTCHA (HTTP 503, segnali come "api-services-support@amazon.com"), applica backoff esponenziale con jitter, e implementa un circuit breaker che sospende le richieste dopo 3 fallimenti consecutivi. Non superare 1000 richieste/ora per keyword.
È legale fare scraping dei risultati di ricerca di Amazon?
La raccolta di dati pubblicamente accessibili (risultati di ricerca, prezzi, posizioni) è generalmente permessa, ma dipende dalla giurisdizione. Negli Stati Uniti, il CFAA si applica all'accesso non autorizzato a sistemi protetti. Nell'UE, il GDPR regola il trattamento di dati personali. Non aggirare misure di sicurezza tecniche (CAPTCHA, rate limiting), rispetta i Termini di Servizio, e considera l'uso di Amazon SP-API dove disponibile. Consulta un legale per il tuo caso specifico.






