Risposta rapida
Come dovrebbe un scraper gestire le risposte 403, 429 e CAPTCHA?
Trattale come segnali, non ostacoli. Su un 429, aspetta Retry-After e riduci il ritmo su quel host. Su un 403, riprova una volta dopo una pausa, poi fermati e controlla le regole del sito. Su un CAPTCHA, ferma quell'host: non risolverlo automaticamente. CrawlRelay proxy residenziali, da 0,50 USD/GB, distribuiscono il carico e impostano la località; non sono un modo per aggirare le decisioni del sito. Senza KYC. Paga in crypto.
I tre segnali a colpo d'occhio
| 429 Troppe Richieste | Sei troppo veloce. Rispetta Retry-After, rallenta, riduci la concorrenza per host |
|---|---|
| 403 Forbidden | Questa richiesta è rifiutata. Un tentativo dopo una pausa, poi ferma e verifica |
| CAPTCHA o pagina di sfida | Il sito vuole sapere se sei umano. Ferma l'host e rallenta |
| Standard per regole di crawling | robots.txt, RFC 9309; Crawl-delay è una comune estensione |
| Cosa non supportiamo | Risoluzione CAPTCHA, plugin stealth, spoofing di fingerprint |
Cosa significa ciascun segnale per il mio crawler?
- 429 è il più gentile: il contenuto è disponibile, ma non al tuo ritmo. È definito da RFC 6585, spesso con un header
Retry-Afterche dice quando tornare. - 403 è un rifiuto di questa richiesta. Può essere risolvibile (paese errato, header mancanti, troppo veloce) o definitivo (il sito non permette accesso automatizzato a quel contenuto).
- Un CAPTCHA o pagina di sfida, spesso servita con status 403 o 503, significa che la gestione bot del sito dubita del tuo traffico. È un'escalation: il passo dopo aver ignorato i 429.
Tutti e tre sono segnali crescenti. I siti che vedono ignorati i loro 429 salgono a 403 e sfide, poi a blocchi lunghi su intere gamme IP, danneggiando tutti gli utenti di quelle gamme.
Cosa dovrebbe fare il mio crawler per ogni segnale?
| Segnale | Prima risposta | Se continua | Fermati quando |
|---|---|---|---|
| 429 | Aspetta Retry-After o rallenta esponenzialmente con jitter | Dimezza la concorrenza su quell'host | Retry-After continua a crescere, o 429 persistono una richiesta alla volta |
| 403 | Un tentativo dopo una pausa, stesso paese | Confronta con un browser dello stesso paese; controlla robots.txt e termini | Un secondo 403 sullo stesso modello URL |
| CAPTCHA / sfida | Metti in pausa l'host per diversi minuti | Riprendi a un ritmo molto più basso | La sfida ritorna anche a ritmo ridotto: il sito non vuole accesso automatizzato |
| 503 con Retry-After | Aspetta come richiesto | Metti in pausa l'host | La maggior parte delle richieste fallisce da più di qualche minuto |
Come costruisco un crawler che risponde correttamente?
Metti le regole nel fetcher, non in ogni spider. Questo invia una richiesta alla volta per host, rispetta robots.txt e il suo Crawl-delay, aspetta Retry-After, e smette di interrogare un host dopo tre rifiuti consecutivi. Considera un robots.txt con codice 4xx come permesso e un 5xx come divieto totale, come specificato da RFC 9309.
import time
import urllib.robotparser
from urllib.parse import urlsplit
import requests
PROXY = "http://USERNAME-country-us:[email protected]:7777"
USER_AGENT = "ExampleCrawler/1.0 (+https://example.com/crawler-info)"
class PoliteFetcher:
"""One request at a time per host; robots.txt, Crawl-delay and Retry-After honoured."""
def __init__(self, min_interval=1.0, max_refusals=3):
self.min_interval, self.max_refusals = min_interval, max_refusals
self.http = requests.Session()
self.http.proxies = {"http": PROXY, "https": PROXY}
self.http.headers["User-Agent"] = USER_AGENT
self.robots, self.next_time, self.refusals = {}, {}, {}
def _robots(self, root):
if root not in self.robots:
rp = urllib.robotparser.RobotFileParser(root + "/robots.txt")
try:
r = self.http.get(root + "/robots.txt", timeout=(10, 30))
if r.status_code >= 500:
rp.parse(["User-agent: *", "Disallow: /"]) # unreachable: assume disallow
else:
rp.parse(r.text.splitlines() if r.status_code == 200 else []) # 4xx: allowed
except requests.RequestException:
rp.parse(["User-agent: *", "Disallow: /"])
self.robots[root] = rp
return self.robots[root]
def get(self, url):
scheme, host = urlsplit(url)[:2]
if self.refusals.get(host, 0) >= self.max_refusals:
return None # this host said no: stop asking
rp = self._robots("%s://%s" % (scheme, host))
if not rp.can_fetch(USER_AGENT, url):
return None
delay = max(self.min_interval, rp.crawl_delay(USER_AGENT) or 0)
wait = self.next_time.get(host, 0) - time.monotonic()
if wait > 0:
time.sleep(wait)
r = self.http.get(url, timeout=(10, 30))
pause = delay
if r.status_code in (429, 503):
retry_after = r.headers.get("Retry-After", "")
pause = max(delay, int(retry_after) if retry_after.isdigit() else 60)
refused = r.status_code in (403, 429) or "captcha" in r.text[:5000].lower()
self.refusals[host] = self.refusals.get(host, 0) + 1 if refused else 0
self.next_time[host] = time.monotonic() + pause
return r
fetcher = PoliteFetcher()
resp = fetcher.get("https://example.com/")
print(resp.status_code if resp is not None else "skipped")Cosa risolve legittimamente un 403?
Diverse cause di 403 sono dalla tua parte, e risolverle è corretto:
- Paese sbagliato. Molti siti servono una sola regione. Punta al paese con
-country-<code>. - Header incompleti. Invia
Accept,Accept-Languagee un user agent onesto con URL di contatto. Un user agent simile a browser su un client HTTP semplice è incoerente e spesso rifiutato. - Il tuo ritmo. Un 403 che parte dopo N richieste è un problema di velocità; rallenta.
Cosa non è una soluzione: ruotare user agent per sembrare tante persone diverse, spoofing di fingerprint browser, o ciclare IP per aggirare un blocco voluto dal sito. Se un sito filtra gamme di hosting per bloccare il traffico automatizzato, un IP residenziale non rende consentito quell'accesso.
Perché non risolvere semplicemente i CAPTCHA?
Perché un CAPTCHA è il sito che ti fa una domanda a cui risponderesti in modo falso. Risolverli automaticamente trasforma un crawler educato in uno strumento costruito per aggirare un controllo di accesso, aumentando il rischio legale: i casi USA del 2026 sullo scraping dei motori di ricerca, Google vs. SerpApi e Reddit vs. SerpApi e altri, si basano su accuse che gli imputati abbiano bypassato un sistema anti-bot secondo la regola anti-circumvention del DMCA. I tribunali non hanno risolto la questione, ma il rischio esiste.
CrawlRelay non supporta la risoluzione dei CAPTCHA né l’elusione del rilevamento bot, e la sua Politica di Uso Accettabile li vieta tramite il gateway. Se ti serve accedere a dati dietro a una sfida, chiedi al sito un accesso, usa la sua API o licenzia i dati.
Quando dovrei contattare il sito invece?
Quando ti serve più di quanto consentano le impostazioni predefinite. Molti siti offrono un’API, un feed dati, un programma partner o semplicemente un limite più alto per un crawler che si identifica e spiega il suo scopo. Inserisci un URL di contatto nel tuo user agent, tieni una pagina che descriva il tuo crawler e come disiscriversi, e rispondi rapidamente ai report di abuso. Un crawler contattabile riceve avvertimenti prima dei blocchi.
403, 429 e CAPTCHA: domande
I proxy residenziali fermano i CAPTCHA?
Non contarci. Un exit proxy residenziale cambia l’IP che il sito vede, non il comportamento del crawler: i CAPTCHA causati dal tuo ritmo o comportamento restano, e sono voluti. Se le sfide continuano anche con basse richieste, il sito non vuole accesso automatizzato a quei contenuti.
Quanto devo aspettare dopo un 429 senza Retry-After?
Inizia con qualche secondo e raddoppia l’attesa dopo ogni nuovo 429, aggiungendo un extra casuale e con un limite massimo di circa un minuto. Quando le richieste hanno successo di nuovo, riprendi a un ritmo più basso rispetto a quello che ha causato il 429, aumentando lentamente mentre il tasso di errore resta stabile.
È permesso ruotare gli IP per evitare i limiti di velocità?
La rotazione distribuisce il carico fra gli exit e permette di scegliere le posizioni, ed è normale. Usare la rotazione per restare sotto un limite per IP mantenendo un ritmo che il sito ha rifiutato è un’elusione. La maggior parte dei termini d’uso lo proibisce, e anche la nostra Politica di Uso Accettabile.
Quale user agent dovrebbe inviare il mio scraper?
Il tuo: un nome, una versione e un URL che spiega il crawler e come contattarti, come ExampleCrawler/1.0 (+https://example.com/crawler-info). Non usare nomi di altri crawler come Googlebot o GPTBot.
Fonti (4)
- RFC 9309: Robots Exclusion Protocol — IETF (2022-09)
- RFC 6585: Codici di stato HTTP aggiuntivi (429) — IETF (2012-04)
- Reddit vs. SerpApi LLC — Loeb & Loeb (2026-08)
- Google vs. SerpApi: il tribunale ha accolto la nostra mozione di archiviazione — SerpApi (2026-07-21)
Proxy residenziali per crawler rispettosi
1,50 USD per 1 GB, 0,50 USD/GB da 50 GB.