Nota legale: raccogli solo dati di ricerca pubblici e monitora i tuoi listing o quelli per cui hai autorizzazione. Negli Stati Uniti, accessi non autorizzati possono ricadere sotto il Computer Fraud and Abuse Act (CFAA); nell'UE, il trattamento di dati personali è disciplinato dal GDPR. Rispetta i ToS di Amazon, il file robots.txt e considera l'Amazon SP-API quando disponibile. Questo articolo è a scopo educativo.
Il monitoraggio posizionamento keyword Amazon con proxy è la base di ogni strategia di marketplace SEO. A differenza di Google, Amazon è contemporaneamente motore di ricerca e storefront: l'algoritmo (A9) premia rilevanza testuale e sales velocity, non solo autorità del dominio. Per seller, agenzie e sviluppatori, tracciare nel tempo la posizione organica di un ASIN per keyword e marketplace è l'unico modo per misurare l'impatto di ottimizzazioni listing, PPC e variazioni di prezzo.
Perché Amazon è un SERP a sé stante
Il amazon serp scraping richiede un approccio diverso dal classico web scraping. Il SERP di Amazon combina risultati organici, sponsorizzati (Sponsored Products), Brand Stores e contenuti editoriali in un'unica griglia. La posizione organica di un ASIN dipende da:
- Rilevanza: match tra query, titolo, bullet point, backend keywords e categoria.
- Sales velocity storica e corrente: conversioni recenti pesano molto.
- Disponibilità e prezzo: out-of-stock e prezzo non competitivo declassano rapidamente.
- Recensioni e rating: volume e media influenzano ranking e CTR.
Questo significa che un ASIN può essere #3 su "cuffie bluetooth" su amazon.it e #12 su amazon.de per la stessa keyword tradotta. Per confrontare apples-to-apples devi fissare marketplace, keyword e ASIN. Senza un amazon keyword rank tracker automatizzato, la copertura su più keyword e marketplace è manualmente impraticabile.
Architettura del flusso di tracking
Un sistema di tracking ha quattro componenti:
- Fetcher: client HTTP (o browser headless) che richiama
https://www.amazon.{tld}/s?k={keyword}&page={n}tramite proxy. - Parser estrae ASIN e posizione dai nodi
[data-component-type="s-search-result"]. - Matcher confronta l'ASIN target con i risultati e registra la posizione organica.
- Storage: SQLite/Postgres con schema
(date, marketplace, keyword, asin, organic_position, sponsored_position).
Il punto critico è il fetcher: Amazon applica anti-bot aggressivo (rate limiting, CAPTCHA, soft-block con redirect a /errors/validateCaptcha) e localizza i risultati per marketplace. Ecco perché i proxy residenziali con geo-targeting sono obbligatori.
Perché servono proxy residenziali con geo-targeting
Amazon decide lingua, valuta e risultati in base a IP, cookie e header Accept-Language. Un datacenter IP tedesco su amazon.com può comunque ricevere risultati localizzati o essere sfidato da CAPTCHA. I proxy residenziali usano IP assegnati a ISP reali, quindi appaiono come traffico consumer legittimo. Con ProxyHat puoi forzare il paese nel username:
user-country-USper amazon.com (USA).user-country-DEper amazon.de (Germania).user-country-ITper amazon.it.
Per paginare i risultati in modo stabile (page 1→5) serve una sessione sticky: lo stesso IP per tutta la keyword, altrimenti Amazon può mostrare risultati inconsistenti tra pagine. ProxyHat supporta -session-{id} nel username.
Setup ProxyHat: formato credenziali
Endpoint HTTP: http://USERNAME:PASSWORD@gate.proxyhat.com:8080. Le flag di geo e sessione vanno nel username.
# HTTP — USA, amazon.com, sessione sticky
http://user-country-US-session-kw1abc:pass@gate.proxyhat.com:8080
# HTTP — Germania, amazon.de
http://user-country-DE-session-kw2def:pass@gate.proxyhat.com:8080
# SOCKS5 (quando serve TLS fingerprint diverso)
socks5://user-country-IT-session-kw3ghi:pass@gate.proxyhat.com:1080
Consulta la pagina locations per la lista dei paesi supportati e pricing per i piani.
Esempio 1: fetch grezzo con curl_cffi
curl_cffi imita il TLS fingerprint di Chrome, utile contro fingerprinting base. Ecco un fetcher minimale con retry e backoff.
# pip install curl_cffi tenacity
from curl_cffi import requests
from tenacity import retry, stop_after_attempt, wait_exponential
import urllib.parse
import time
PROXY = "http://user-country-US-session-kw1abc:pass@gate.proxyhat.com:8080"
def build_url(keyword: str, page: int, tld: str = "com") -> str:
q = urllib.parse.quote(keyword)
return f"https://www.amazon.{tld}/s?k={q}&page={page}"
@retry(stop=stop_after_attempt(4), wait=wait_exponential(multiplier=2, min=2, max=30))
def fetch_page(keyword: str, page: int, tld: str = "com") -> str:
url = build_url(keyword, page, tld)
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 "
"(KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36",
"Accept-Language": "en-US,en;q=0.9",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
}
r = requests.get(url, headers=headers, proxies={"http": PROXY, "https": PROXY},
impersonate="chrome124", timeout=30)
if r.status_code != 200 or "validateCaptcha" in r.url:
raise RuntimeError(f"blocked or captcha: {r.status_code} {r.url}")
time.sleep(1.5) # throttle
return r.text
html = fetch_page("wireless earbuds", 1, "com")
print(len(html))
Esempio 2: parsing del SERP
Il selettore chiave è [data-component-type="s-search-result"]. Ogni card ha data-asin. I prodotti sponsorizzati contengono un'etichetta "Sponsored" (testo o attributo aria-label).
# pip install lxml selectolax
from selectolax.parser import HTMLParser
from dataclasses import dataclass
@dataclass
class SerpItem:
asin: str
organic_position: int
is_sponsored: bool
page: int
def parse_serp(html: str, page: int) -> list[SerpItem]:
tree = HTMLParser(html)
cards = tree.css('[data-component-type="s-search-result"]')
items = []
organic_idx = 0
for card in cards:
asin = card.attributes.get("data-asin", "")
if not asin:
continue
# detect Sponsored label
sponsored_node = card.css_first('span.a-color-secondary')
is_sponsored = False
if sponsored_node and "Sponsored" in (sponsored_node.text() or ""):
is_sponsored = True
if not is_sponsored:
organic_idx += 1
pos = organic_idx
else:
pos = -1 # non organico
items.append(SerpItem(asin=asin, organic_position=pos,
is_sponsored=is_sponsored, page=page))
return items
items = parse_serp(html, 1)
for it in items[:5]:
print(it)
Nota: la struttura HTML di Amazon cambia spesso. Verifica i selettori con un dump locale prima di andare in produzione e aggiungi fallback (es. ricerca testo "Sponsored" in tutto il card).
Esempio 3: tracker completo con storico
Combina fetch + parse + match ASIN + storage SQLite. Usa una sessione sticky per tutta la keyword.
# pip install curl_cffi tenacity selectolax
import sqlite3
import time
import urllib.parse
from curl_cffi import requests
from tenacity import retry, stop_after_attempt, wait_exponential
from selectolax.parser import HTMLParser
from datetime import date
DB = "rank.db"
def init_db():
con = sqlite3.connect(DB)
con.execute("""CREATE TABLE IF NOT EXISTS ranks(
d DATE, marketplace TEXT, keyword TEXT, asin TEXT,
organic_pos INT, sponsored_pos INT, page INT,
PRIMARY KEY(d, marketplace, keyword, asin))""")
con.commit(); con.close()
PROXY_TMPL = "http://user-country-{cc}-session-{sid}:pass@gate.proxyhat.com:8080"
@retry(stop=stop_after_attempt(4), wait=wait_exponential(multiplier=2, min=2, max=30))
def fetch(keyword, page, tld, cc, sid):
q = urllib.parse.quote(keyword)
url = f"https://www.amazon.{tld}/s?k={q}&page={page}"
proxy = PROXY_TMPL.format(cc=cc, sid=sid)
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 "
"(KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36",
"Accept-Language": "en-US,en;q=0.9",
}
r = requests.get(url, headers=headers, proxies={"http": proxy, "https": proxy},
impersonate="chrome124", timeout=30)
if r.status_code != 200 or "validateCaptcha" in r.url:
raise RuntimeError(f"blocked: {r.status_code}")
time.sleep(1.2)
return r.text
def parse(html, page):
tree = HTMLParser(html)
out = []
oidx = 0
for card in tree.css('[data-component-type="s-search-result"]'):
asin = card.attributes.get("data-asin", "")
if not asin:
continue
sp = card.css_first('span.a-color-secondary')
is_sp = bool(sp and "Sponsored" in (sp.text() or ""))
if not is_sp:
oidx += 1
out.append((asin, oidx, -1, page))
else:
out.append((asin, -1, page, page)) # sponsored_pos approssimato
return out
def track(keyword, target_asin, tld, cc, max_pages=5):
sid = f"{keyword[:4]}{target_asin[:4]}"
today = date.today().isoformat()
con = sqlite3.connect(DB)
found = None
for page in range(1, max_pages + 1):
try:
html = fetch(keyword, page, tld, cc, sid)
except Exception as e:
print(f"page {page} failed: {e}")
break
for asin, opos, spos, pg in parse(html, page):
if asin == target_asin and opos != -1:
found = opos
con.execute("INSERT OR REPLACE INTO ranks VALUES(?,?,?,?,?,?,?)",
(today, tld, keyword, asin, opos, spos, pg))
con.commit()
if found:
break
con.close()
return found
init_db()
pos = track("wireless earbuds", "B0CX22VV5R", "com", "US", max_pages=5)
print(f"organic position: {pos}")
Esempio 4: Playwright per SERP pesanti
Quando Amazon serve risultati via JS o serve un challenge, un browser headless è più robusto. Playwright supporta proxy con autenticazione.
# pip install playwright && playwright install chromium
from playwright.sync_api import sync_playwright
def track_pw(keyword, target_asin, tld="com", cc="US", max_pages=3):
sid = f"pw{keyword[:4]}"
proxy_user = f"user-country-{cc}-session-{sid}"
with sync_playwright() as p:
browser = p.chromium.launch(
proxy={"server": "http://gate.proxyhat.com:8080",
"username": proxy_user, "password": "pass"},
headless=True)
ctx = browser.new_context(user_agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
"AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36",
locale="en-US", extra_http_headers={"Accept-Language": "en-US,en;q=0.9"})
page = ctx.new_page()
import urllib.parse, time
found = None
for n in range(1, max_pages + 1):
url = f"https://www.amazon.{tld}/s?k={urllib.parse.quote(keyword)}&page={n}"
page.goto(url, timeout=45000, wait_until="domcontentloaded")
if "validateCaptcha" in page.url:
print("captcha at page", n); break
cards = page.query_selector_all('[data-component-type="s-search-result"]')
oidx = 0
for c in cards:
asin = c.get_attribute("data-asin")
if not asin: continue
txt = c.inner_text()
is_sp = "Sponsored" in txt
if not is_sp:
oidx += 1
if asin == target_asin:
found = oidx
break
if found: break
time.sleep(1.5)
browser.close()
return found
print(track_pw("wireless earbuds", "B0CX22VV5R"))
Esempio 5: scheduler giornaliero con circuituito
# pip install apscheduler
from apscheduler.schedulers.blocking import BlockingScheduler
import logging
logging.basicConfig(level=logging.INFO)
JOBS = [
("wireless earbuds", "B0CX22VV5R", "com", "US"),
("kabellose kopfhörer", "B0CX22VV5R", "de", "DE"),
]
def run_all():
for kw, asin, tld, cc in JOBS:
try:
pos = track(kw, asin, tld, cc, max_pages=5)
logging.info(f"{kw} @ {tld} -> pos {pos}")
except Exception as e:
logging.error(f"{kw} failed: {e}")
sched = BlockingScheduler()
sched.add_job(run_all, "cron", hour=7, minute=30)
run_all() # test
sched.start()
Production tips
- Throttle: 1–2 richieste/sec per sessione, pausa 1–2s tra le pagine. Più concorrenza = più IP distinti (una sessione per keyword).
- Retry con backoff: usa
tenacitycon wait esponenziale 2–30s e max 4 tentativi. Distingui 503 (retry) da 200+CAPTCHA (cambia IP/sessione). - CAPTCHA detection: controlla
"validateCaptcha" in r.urlo la presenza diform action="/errors/validateCaptcha". Al CAPTCHA, ruota sessione e riprova dopo 60s. - Indexation check: prima di tracciare la posizione, verifica che l'ASIN sia indicizzato per quella keyword: se dopo 5 pagine non compare, registra
NULL(non0) per distinguerlo da "non trovato in page 1". - Soft 200: a volte Amazon risponde 200 con una pagina vuota o di errore. Verifica la presenza di almeno N card (
len(cards) > 5). - Header realistici: mantieni
Accept-Languagecoerente con il marketplace (es.de-DE,de;q=0.9per amazon.de). - Monitoring: logga tasso di successo per sessione; se scende sotto il 90%, riduci la concorrenza o cambia pool.
Confronto: curl_cffi vs Playwright vs SP-API
| Approccio | Velocità | Robustezza anti-bot | Costo | Quando usarlo |
|---|---|---|---|---|
| curl_cffi + proxy residenziali | ~200ms/page | Media-alta | Basso | Tracking di massa, keyword list > 100 |
| Playwright + proxy residenziali | ~1.5s/page | Alta | Medio | SERP JS-heavy, challenge avanzate |
| Amazon SP-API (Product/Reports) | n/a (API) | Massima (ufficiale) | Gratuito per seller | Quando serve solo catalog/own data |
Nota: lo SP-API non espone direttamente la posizione organica per keyword arbitraria; per quello serve il SERP scraping. Combina i due quando possibile. Per pattern di scraping generali vedi web scraping e SERP tracking; per dettagli tecnici consulta la documentazione ProxyHat.
Errori comuni e edge case
- Posizione sponsorizzata contata come organica: il 30–50% delle prime posizioni su keyword commerciali è Sponsored. Separa sempre i due flussi.
- Marketplace sbagliato: amazon.com con IP IT può restituire risultati localizzati o redirect. Forza
-country-USeAccept-Language: en-US. - Sessione non sticky: pagine 1 e 2 con IP diverso possono mostrare ordering differente. Usa
-session-{id}per tutta la keyword. - Paginazione oltre page 5–7: Amazon spesso non serve oltre; tronca e registra
NULL. - Variazioni di layout: A/B test di Amazon cambiano selettori; aggiungi test di smoke sul parser.
Etica e conformità
- Traccia i tuoi listing o dati pubblici; evita scraping massivo di concorrenti per scopi non autorizzati.
- Throttle ragionevole: non saturare la capacità del marketplace.
- Rispetta
robots.txte i ToS; considera lo SP-API per dati ufficiali. - Non memorizzare dati personali (recensori); se lo fai, applica GDPR (base giuridica, conservazione).
Key takeaways
- Amazon è un SERP proprietario: traccia posizione organica per keyword, marketplace e ASIN.
- Proxy residenziali con geo-targeting (
-country-US/DE/IT) e sessioni sticky sono obbligatori.- Parser basato su
[data-component-type="s-search-result"]+data-asin+ label "Sponsored".- curl_cffi per velocità, Playwright per robustezza; SP-API per dati ufficiali.
- Production: throttle, retry/backoff, CAPTCHA detection, indexation check, monitoring del tasso di successo.
FAQ
Cos'è il monitoraggio posizionamento keyword Amazon con proxy?
È la raccolta periodica del SERP Amazon tramite proxy residenziali geo-localizzati, il parsing della posizione organica di un ASIN per keyword e marketplace, e la memorizzazione dello storico per analisi SEO e competitive.
Perché è importante per chi usa proxy?
Perché l'algoritmo A9 premia sales velocity e rilevanza, e la posizione varia per marketplace; senza proxy residenziali con geo-targeting i risultati sono localizzati in modo inconsistente e i soft-block sono frequenti.
Quale tipo di proxy è migliore?
Proxy residenziali con geo-targeting per paese e sessioni sticky: IP ISP reali, localizzazione per-marketplace stabile, rotazione controllata per evitare anti-bot.
Come evitare i blocchi?
Throttle 1–2 req/s, retry con backoff esponenziale, detection di CAPTCHA/redirect, header realistici e rotazione di sessione per keyword. Monitora il tasso di successo e fermati sotto il 90%.
Playwright o curl_cffi?
curl_cffi per tracking di massa (~200ms/page); Playwright per SERP JS-heavy o challenge avanzate (~1.5s/page). Combina con SP-API per dati ufficiali quando disponibili.





