Il tuo spider Scrapy parte a razzo su 100 pagine di test, poi si schianta quando arriva a quota 10.000. In realtà non è davvero un bug di scraping: è un problema di rete mascherato da bug di scraping. La soluzione a cui tutti ricorrono è un proxy, e inserirlo in request.meta ti prende più o meno trenta secondi.
Il problema è che quella soluzione da trenta secondi è proprio il punto in cui molti tutorial si fermano. Ti mostrano meta={"proxy": "http://IP:PORT"}, magari una classe middleware, e considerano il lavoro chiuso. Però spesso saltano i casi veri: cosa succede quando il proxy muore a metà crawl, come evitare che le credenziali finiscano nella cronologia di Git, o perché un retry può riusare lo stesso proxy fallito. Sono proprio queste esigenze di produzione che questa guida affronta: configurazione fail-closed, gestione dei segreti, selezione intenzionale del proxy nei retry, limiti di protocollo e trade-off di costo misurabili.
Cos'è un Proxy Middleware in Scrapy?
Un proxy middleware è un pezzo di codice che si inserisce nella pipeline di download di Scrapy e decide da quale indirizzo IP una richiesta deve sembrare arrivare, prima che venga mandata in rete. Scrapy include già un middleware integrato, HttpProxyMiddleware, che legge la chiave proxy da request.meta, aggiunge l’autenticazione del proxy se serve e passa la richiesta al download handler che apre davvero la connessione. Un proxy middleware personalizzato non sostituisce quel passaggio di trasporto: è un selettore che sceglie quale proxy usare prima che entri in gioco il meccanismo integrato. La differenza conta più di quanto sembri, ed è spesso la radice della maggior parte dei ticket del tipo "il mio middleware personalizzato non funziona".
Perché i Proxy Sono Importanti nei Progetti Scrapy in Produzione
Un proxy modifica il percorso di rete e l’IP sorgente apparente. Può essere utile per test geografici legittimi, per distribuire traffico autorizzato e per isolare guasti di rete. Non dà permessi, non aggira i rate limit e non garantisce l’accesso. Se un crawl ha davvero bisogno di un proxy dipende dal target, dai suoi termini, dalla frequenza delle richieste e dai requisiti di affidabilità del job.
Non tutti i proxy sono uguali, e scegliere il livello sbagliato è già di per sé un incidente di produzione:
| Tipo di proxy | Affidabilità | Velocità | Rischio di rilevamento | Costo tipico |
|---|---|---|---|---|
| Proxy pubblici gratuiti | Molto variabile | Variabile | Spesso elevato | Nessun costo, ma rischio operativo e di sicurezza concreto |
| Proxy datacenter | Dipende dal provider e dal target | Spesso veloci | Dipende dal target | Di solito a GB o per IP |
| Proxy residential | Dipende dal provider e dal target | Variabile | Dipende dal target | Di solito a GB |
| Proxy ISP | Dipende dal provider e dal target | Variabile | Dipende dal target | Specifico del provider |
Vale la pena fare una nota specifica sui proxy gratuiti perché i rischi osservati sono tutt’altro che banali. Lo studio di 30 mesi Free Proxies Unmasked ha monitorato oltre 640.000 indirizzi di 11 provider: il 34,5% è stato attivo almeno una volta e 16.923 hanno alterato i contenuti. Questi dati sono un avvertimento forte per le liste pubbliche; non sono un tasso di fallimento valido per ogni lista attuale, pool a pagamento, target o carico di lavoro.
In più, i proxy non aggirano magicamente i moderni sistemi di bot detection. Servizi come Cloudflare valutano le richieste usando decine di segnali — fingerprint TLS, coerenza degli header, esecuzione JavaScript, pattern comportamentali — dove l’IP è solo uno dei fattori. Un proxy residential pulito, ma usato in una richiesta con header incoerenti e senza cookie jar, verrà comunque segnalato. Tieni ben presenti queste aspettative prima di costruire un’intera architettura basata sul semplice "ruoto l’IP".
Prima di Iniziare
- Difficoltà : Intermedia
- Tempo richiesto: ~30–45 minuti per la configurazione completa in produzione, ~5 minuti per il test rapido
- Cosa ti serve: Python 3.9+, Scrapy installato (questa guida è testata su Scrapy 2.17.0, rilasciato nel luglio 2026), uno spider funzionante creato con
scrapy startprojecte almeno un endpoint proxy (per i test va benissimo una trial gratuita di qualunque provider di proxy datacenter)
Passo 1: Testare un Proxy con il Parametro Request Meta
Il modo più veloce per verificare che un proxy funzioni è aggirare del tutto l’architettura dei middleware e provarlo direttamente.
Il HttpProxyMiddleware integrato in Scrapy legge la chiave proxy direttamente da request.meta e instrada la richiesta attraverso quel proxy. Nessuna modifica alle impostazioni, nessuna classe middleware: basta un solo argomento keyword.
import scrapy
class ProxyTestSpider(scrapy.Spider):
name = "proxy_test"
start_urls = ["https://httpbin.org/ip"]
def start_requests(self):
for url in self.start_urls:
yield scrapy.Request(
url,
meta={"proxy": "http://203.0.113.10:8080"},
callback=self.parse,
)
def parse(self, response):
self.logger.info(response.text)
Eseguilo con scrapy runspider proxy_test.py. Se il proxy funziona, httpbin.org/ip restituirà l’IP del proxy invece del tuo: quella è la conferma. Se invece la risposta si blocca e alla fine compare un errore TCP connection timed out, il proxy è morto o irraggiungibile, cosa che — sorpresa — succede più spesso di quanto i vendor di proxy ammettano.
Questo metodo va bene per spider usa-e-getta o test rapidi. Diventa ingestibile appena hai più di uno spider, perché a quel punto stai scrivendo la stessa stringa proxy in cinque file diversi.
Passo 2: Creare un Proxy Middleware Personalizzato
Per tutto ciò che va oltre uno spider singolo, conviene centralizzare la logica del proxy in un solo punto. Crea una classe ProxyMiddleware nel file middlewares.py del progetto:
from scrapy.exceptions import NotConfigured
class ProxyMiddleware:
def __init__(self, proxy_url):
self.proxy_url = proxy_url
@classmethod
def from_crawler(cls, crawler):
proxy_url = crawler.settings.get("PROXY_URL")
if not proxy_url:
raise NotConfigured("PROXY_URL è obbligatorio; nessun fallback diretto silenzioso")
return cls(proxy_url=proxy_url)
def process_request(self, request, spider):
if "proxy" not in request.meta:
request.meta["proxy"] = self.proxy_url
E registrala in settings.py:
import os
PROXY_URL = os.environ.get("PROXY_URL")
DOWNLOADER_MIDDLEWARES = {
"myproject.middlewares.ProxyMiddleware": 350,
}
Nota il metodo di classe from_crawler invece di un semplice __init__. È il pattern che Scrapy raccomanda davvero per leggere le impostazioni, ed è lo stesso hook che useremo di nuovo al Passo 4 quando parleremo dei segreti. Il vantaggio qui è chiarissimo: cambi una sola impostazione e tutti gli spider del progetto usano il nuovo proxy. Niente più caccia all’IP vecchio in cinque file diversi.
Passo 3: Capire l'Ordine di Esecuzione dei Middleware (Così il Proxy Non Sembra Inattivo)
Qui c’è la parte che quasi tutti i tutorial liquidano con un "metti la priorità a 350, fidati". I downloader middleware di Scrapy seguono un ordine preciso e prevedibile, e se non lo capisci il setup proxy ti produrrà bug che sembrano non c’entrare nulla con i proxy.
Gli hook lato richiesta (process_request) vengono eseguiti in ordine di priorità crescente — prima il numero più basso. Gli hook lato risposta (process_response, process_exception) vengono eseguiti in ordine decrescente — prima il numero più alto, risalendo la catena al contrario.
Flusso richiesta (crescente):
Spider → [100] RobotsTxt → [300] HttpAuth → [350] IL TUO PROXY MIDDLEWARE
→ [500] UserAgent → [550] Retry → [700] Cookies → [750] HttpProxy
→ Downloader
Flusso risposta (decrescente):
Downloader → [750] HttpProxy → [700] Cookies → [550] Retry
→ [500] UserAgent → [350] IL TUO PROXY MIDDLEWARE → [300] HttpAuth
→ [100] RobotsTxt → Spider
Ecco la tabella reale e aggiornata delle priorità di default dei middleware integrati di Scrapy (verificata su 2.17.0):
| Middleware | Priorità predefinita |
|---|---|
| RobotsTxtMiddleware | 100 |
| HttpAuthMiddleware | 300 |
| DownloadTimeoutMiddleware | 350 |
| DefaultHeadersMiddleware | 400 |
| UserAgentMiddleware | 500 |
| RetryMiddleware | 550 |
| RedirectMiddleware | 600 |
| CookiesMiddleware | 700 |
| HttpProxyMiddleware | 750 |
| DownloaderStats | 850 |
| HttpCacheMiddleware | 900 |
Quando RetryMiddleware programma un retry, copia la richiesta fallita — inclusi i metadati — e quella nuova richiesta rientra nella catena dei downloader middleware. Il rapporto numerico del selettore con la priorità 550 non garantisce la rotazione. La rotazione avviene solo quando il codice del selettore riconosce il retry e sovrascrive in modo intenzionale il meta["proxy"] copiato. La priorità 350 è un punto comodo per un selettore perché entra in gioco prima del passaggio di trasporto integrato a 750, ma da sola non è un meccanismo di rotazione.

Errori Comuni nell'Ordinamento dei Middleware
- Impostare il middleware alla stessa priorità di
HttpProxyMiddleware(750): crea una race condition in cui è l’ordine del dict di Scrapy — non la tua logica — a decidere quale middleware processa prima la richiesta. Sintomo: comportamento del proxy intermittente e inspiegabile. - Usare
setdefault()oif "proxy" not in request.metain un selettore con rotazione: il retry copiato conserva il proxy precedente. Sintomo: ogni retry ripete lo stesso percorso fallito. Soluzione: rilevare un retry (per esempio,retry_times > 0) e sostituire esplicitamente il valore proxy gestito dal selettore. - Disabilitare del tutto
HttpProxyMiddleware: alcuni tutorial suggeriscono di impostare"scrapy.downloadermiddlewares.httpproxy.HttpProxyMiddleware": Noneperché "ci pensa il middleware personalizzato". In realtà no: il middleware personalizzato è un selettore, non uno strato di trasporto. Disabilitare quello integrato significa che gli header di autenticazione del proxy non vengono mai aggiunti e le richieste escono senza autenticazione (o non escono affatto).
Passo 4: Smettere di Hardcodare le Credenziali del Proxy
Ogni tutorial Scrapy sui proxy che compare in alto scrive http://username:password@proxy.example.com:8080 direttamente in un file Python. Quella è una credenziale che resta per sempre nella cronologia di Git, in ogni clone, in ogni fork, in ogni dump di log se qualcuno usa con leggerezza dei print().
In pratica ci sono tre livelli per farlo:
| Metodo | Sicurezza | Flessibilità | Ideale per |
|---|---|---|---|
| Hardcoded in spider/settings.py | Debole — i segreti restano nel repo | Bassa | Solo test locali rapidi |
Variabile d'ambiente http_proxy (nativa di Scrapy) | Migliore — fuori dal codice | Bassa (un solo proxy) | Pipeline CI/CD, Docker |
File .env + python-dotenv + from_crawler | La migliore — fuori dal codice, per ambiente | Alta (più proxy, rotazione) | Scraper in produzione |
La terza opzione vale la pena farla bene. Installa python-dotenv, crea un file .env e aggiungilo subito a .gitignore — davvero, fallo adesso:
PROXY_USER=myuser
PROXY_PASSWORD=my$ecret!Pass
PROXY_HOST=proxy.example.com
PROXY_PORT=8080
Caricalo all’inizio di settings.py:
from dotenv import load_dotenv
import os
load_dotenv()
PROXY_USER = os.getenv("PROXY_USER")
PROXY_PASSWORD = os.getenv("PROXY_PASSWORD")
PROXY_HOST = os.getenv("PROXY_HOST")
PROXY_PORT = os.getenv("PROXY_PORT")
Poi leggilo in modo sicuro nel middleware tramite from_crawler — è il pattern che risolve esattamente la confusione che vedo spesso nei forum, dove la domanda è: "come faccio a impostarlo prima di eseguire scrapy crawl se le credenziali cambiano a ogni run?":
import os
from urllib.parse import quote
class SecureProxyMiddleware:
def __init__(self, user, password, host, port):
self.user = quote(user, safe="")
self.password = quote(password, safe="")
self.host = host
self.port = port
@classmethod
def from_crawler(cls, crawler):
settings = crawler.settings
return cls(
user=settings.get("PROXY_USER"),
password=settings.get("PROXY_PASSWORD"),
host=settings.get("PROXY_HOST"),
port=settings.get("PROXY_PORT"),
)
def process_request(self, request, spider):
proxy_url = f"http://{self.user}:{self.password}@{self.host}:{self.port}"
request.meta["proxy"] = proxy_url
Nota la chiamata a urllib.parse.quote() attorno alle credenziali. Se la password contiene @, : o / (e i generatori di password adorano metterli), il parsing dell’URL si rompe a meno che non vengano percent-encoded prima. È una correzione di una sola riga che ti evita un’ora imbarazzante di debug di errori "invalid proxy URL" che non hanno nulla a che vedere con il proxy in sé.
Tieni le credenziali fuori dai log e verifica il percent-encoding con valori rappresentativi ma finti. HTTPS tunneling, SOCKS5 e credenziali non latine hanno limiti che dipendono dall’handler; non dare per scontato che un pattern di autenticazione funzioni ovunque senza un test di integrazione bloccato su quella configurazione specifica.

Passo 5: Aggiungere la Rotazione dei Proxy
Un singolo proxy — anche se buono — che fa 5.000 richieste sullo stesso sito prima o poi viene segnalato. Ti serve un pool.
Opzione A — costruirlo da solo. È davvero semplice:
import random
class RotatingProxyMiddleware:
def __init__(self, proxy_pool):
self.proxy_pool = proxy_pool
@classmethod
def from_crawler(cls, crawler):
return cls(proxy_pool=crawler.settings.getlist("PROXY_POOL"))
def process_request(self, request, spider):
request.meta["proxy"] = random.choice(self.proxy_pool)
Questo funziona per usi basilari ma non sa nulla di quali proxy siano davvero vivi. Stai tirando i dadi a ogni richiesta.
Opzione B — usare scrapy-rotating-proxies. Questo pacchetto di terze parti aggiunge di default il rilevamento dei ban e il backoff automatico:
pip install scrapy-rotating-proxies
Qui però devo essere onesto: l'ultima release su PyPI è la versione 0.6.2, datata 2019, e il progetto è etichettato come Alpha. Non vuol dire per forza che sia rotto con le versioni moderne di Scrapy, ma "non mantenuto attivamente dal 2019" non equivale a "collaudato per il traffico di produzione del 2026". Blocca la versione, testalo sui target reali e non dare per scontato che gestisca endpoint proxy autenticati — in gran parte non lo fa.
Passo 6: Costruire un Middleware Proxy Tollerante ai Guasti (Rilevamento dei Proxy Morti)
Questa è la sezione che ogni tutorial concorrente salta del tutto, ed è la differenza tra una demo e qualcosa che regge un crawl di 6 ore senza supervisione.
| Scenario | Cosa mostrano la maggior parte dei tutorial | Cosa aggiunge questo middleware |
|---|---|---|
| Il proxy restituisce 407 | Non trattato | Lo considera un fallimento di autenticazione del proxy |
| Il target restituisce 403/429 | Spesso raggruppati insieme | Mantiene separati i segnali di policy/rate limit dallo stato del proxy |
| Il proxy va in timeout | Non trattato | Soglia di timeout configurabile, decadimento del punteggio di salute |
| Tutti i proxy sono morti | Non trattato | Fallback graduale o pausa del crawl con warning nel log |
| Proxy instabile (intermittente) | Non trattato | Periodo di raffreddamento prima di reinserirlo nel pool |
import time
import random
from scrapy.exceptions import IgnoreRequest
class FaultTolerantProxyMiddleware:
MAX_FAILURES = 3
COOLDOWN_SECONDS = 300
def __init__(self, proxy_pool):
self.pool = {p: {"failures": 0, "banned_until": 0} for p in proxy_pool}
@classmethod
def from_crawler(cls, crawler):
return cls(proxy_pool=crawler.settings.getlist("PROXY_POOL"))
def _healthy_proxies(self):
now = time.time()
return [p for p, s in self.pool.items() if s["banned_until"] < now]
def process_request(self, request, spider):
healthy = self._healthy_proxies()
if not healthy:
spider.logger.warning("Tutti i proxy sono non affidabili — pausa del crawl")
raise IgnoreRequest("Nessun proxy affidabile disponibile")
request.meta["proxy"] = random.choice(healthy)
def process_response(self, request, response, spider):
proxy = request.meta.get("proxy")
if proxy and response.status == 407:
self._mark_failure(proxy)
return response
def process_exception(self, request, exception, spider):
proxy = request.meta.get("proxy")
if proxy:
self._mark_failure(proxy)
def _mark_failure(self, proxy):
state = self.pool[proxy]
state["failures"] += 1
if state["failures"] >= self.MAX_FAILURES:
state["banned_until"] = time.time() + self.COOLDOWN_SECONDS
state["failures"] = 0
Alcune note nate dall’averlo costruito davvero: non trattare ogni 403 come prova che il proxy sia morto — RFC 9110 definisce il 403 come "il server ha capito ma rifiuta", il che può benissimo significare che sono sospetti gli header o la sessione, a prescindere dal proxy. Un 407, invece, significa che è il proxy stesso a rifiutare l’autenticazione: un segnale molto più forte e specifico. Mischiare questi segnali nello stesso contenitore è il modo più veloce per bruciare proxy sani senza motivo.
Tieni espliciti in produzione i retry temporanei di Scrapy, così chi legge il codice può vedere chiaramente la policy:
RETRY_HTTP_CODES = [500, 502, 503, 504, 522, 524, 408, 429]
RETRY_TIMES = 2
Questi sono i default di Scrapy 2.17. Non aggiungere in massa 403 o 407: il 403 è un rifiuto del target con molte possibili cause, mentre il 407 è un problema di autenticazione del proxy che un retry generico della richiesta non risolve. Se un contratto specifico del target giustifica il retry di un altro stato, documenta il motivo e testalo separatamente.

Passo 7: Un Pattern Misurato di Proxy-on-Retry
Alcuni target autorizzati possono restituire contenuto valido direttamente e richiedere un proxy solo dopo una risposta transitoria documentata. Questo può ridurre i byte inviati via proxy, ma non esiste una percentuale universale difendibile di risparmio né un tasso portabile di successo delle richieste dirette. Misura il tuo carico di lavoro prima di adottare il pattern.
Usa l’helper pubblico get_retry_request() di Scrapy e limita l’escalation agli stati specifici del target che hai classificato in modo esplicito. Questo esempio tratta 429 e 503 come segnali di pressione che giustificano il retry; esclude volutamente 403 e 407.
from scrapy.downloadermiddlewares.retry import get_retry_request
class CostAwareEscalationMiddleware:
def process_response(self, request, response, spider):
if response.status not in {429, 503}:
return response
retry = get_retry_request(
request,
spider=spider,
reason=f"proxy_escalation_{response.status}",
max_retry_times=2,
)
if retry is None:
return response
current_tier = request.meta.get("proxy_tier", "direct")
if current_tier == "direct":
retry.meta["proxy"] = spider.settings["DATACENTER_PROXY"]
retry.meta["proxy_tier"] = "datacenter"
elif current_tier == "datacenter":
retry.meta["proxy"] = spider.settings["RESIDENTIAL_PROXY"]
retry.meta["proxy_tier"] = "residential"
else:
return response
return retry
Registra il tasso di contenuti validi in accesso diretto, il tasso di contenuti validi tramite proxy, i byte per record andato a buon fine, i retry per successo e la latenza aggiunta. Un design direct-first è accettabile solo quando l’accesso diretto è autorizzato e il sistema fallisce in modo chiuso ogni volta che è richiesto un proxy. Il risparmio è la riduzione misurata del traffico via proxy, non una percentuale presunta.
Quando Gestire i Proxy in Modo Autonomo Non Conviene
Voglio essere chiaro invece di fingere che tutto il resto dell’articolo fosse inutile: tutto ciò che hai letto sopra è vera ingegneria ed è utile, e per molti progetti — crawl ad alto volume, pipeline personalizzate, tutto ciò in cui serve controllo totale sulla schedulazione delle richieste — è la scelta giusta.
Ma se il tuo obiettivo reale è "ottenere dati strutturati da questa pagina" più che "gestire l’infrastruttura proxy", allora un’API di estrazione potrebbe essere il confine migliore. La documentazione attuale di Thunderbit per POST /extract accetta l’URL di una pagina e uno schema JSON opzionale; quando lo schema viene omesso, il servizio può generarlo dal contenuto della pagina. L’endpoint espone anche le modalità di rendering none, basic e full, oltre ai controlli di timeout e di attesa post-caricamento. L’estrazione solo tramite prompt non fa parte della superficie richiesta attualmente supportata, quindi le integrazioni di produzione vanno costruite attorno al contratto documentato dello schema. Questo sposta l’interfaccia di estrazione dietro una sola richiesta; non promette in modo universale di risolvere qualunque target anti-bot o CAPTCHA.
| Fattore | Scrapy + proxy fai-da-te | Estrazione via API (es. Thunderbit) |
|---|---|---|
| Sforzo iniziale | Alto — middleware, rotazione, logica di retry | Basso — una chiamata API con uno schema |
| Comportamento di rete/rendering | Configuri handler, proxy, header e ritardi | Controllato tramite opzioni API documentate |
| Manutenzione | Gestisci tu selettori, salute del pool e cambi del target | Gestisci tu la qualità dello schema, la validazione e il comportamento di integrazione |
| Modello di costo | Fee dei proxy + compute + tempo di engineering | La documentazione attuale indica 20 unità per pagina (verificato 2026-08-10) |
| Controllo | Totale — pipeline personalizzate, catena di middleware | Limitato alle capacità dell'API |
| Ideale per | Crawl complessi, alto volume, logica custom | Estrazione mirata, prototipazione, enrichment |
Se stai soprattutto estraendo pagine strutturate per liste di lead, dati prodotto o ricerca, fai un pilot rappresentativo con la Thunderbit Chrome Extension o con l’API e confronta record validi, latenza, unità e tempo di manutenzione. Se il tuo progetto richiede grafo di crawl personalizzati e controllo della pipeline, Scrapy resta la scelta più forte.
Approfondisci
Consigli e Errori Comuni
- Consiglio: testa i proxy su
httpbin.org/ipprima di puntarli a un target reale. È il modo più rapido per verificare che il routing funzioni prima di aggiungere complessità sopra. - Errore comune: impostare un proxy in
request.headersinvece che inrequest.meta. È un bug davvero frequente, quasi da refuso:HttpProxyMiddlewarelegge solometa["proxy"], e un tentativo basato su header fallisce in silenzio senza errori evidenti. - Errore comune: pensare che i proxy HTTP e HTTPS si configurino allo stesso modo. Un URL proxy HTTP verso una destinazione HTTPS in genere funziona tramite tunneling CONNECT con un handler compatibile, ma usare lo schema
https://per l’endpoint del proxy è una configurazione diversa e meno supportata: non confondere le due cose. - Consiglio: se ti serve il supporto SOCKS5, controlla prima le capacità del download handler della tua versione di Scrapy. L’handler Httpx sperimentale di Scrapy 2.17 ha aggiunto il supporto SOCKS5 tramite
httpx[socks], ma resta etichettato come sperimentale: non costruire una dipendenza di produzione senza test tuoi.
Metodi Alternativi
Oltre a scrapy-rotating-proxies, alcuni team instradano tutta la logica proxy attraverso un gateway del provider — un singolo URL proxy in cui il vendor gestisce dietro le quinte rotazione, stickiness di sessione e geo-targeting. Questo compromesso sacrifica un po’ di controllo in cambio di molta meno logica middleware, e vale la pena confrontarne il costo con quello di un pool gestito in autonomia prima di costruirlo da zero.
Conclusione
Impostare un proxy in Scrapy richiede una sola riga. Far sì che quella configurazione regga un vero crawl di produzione richiede una policy di fallimento esplicita, credenziali protette, limiti degli handler testati e codice selettore che sostituisca consapevolmente i metadati proxy copiati in caso di retry. Se ti porti via due abitudini, fai in modo che siano queste: fallire in modo chiuso quando un proxy è necessario e non committare mai la password di un proxy in un file Python.
FAQ
Come configuro un proxy personalizzato in Scrapy con autenticazione?
Usa il formato URL protocol://username:password@host:port, ma prima percent-encode di username e password con urllib.parse.quote() se contengono caratteri speciali. In produzione, leggi quelle credenziali tramite un metodo di classe from_crawler che le recuperi da variabili d’ambiente invece di hardcodarle.
Che numero di priorità dovrei usare per il mio middleware proxy personalizzato in Scrapy?
350 è una priorità comune per un selettore perché viene eseguita prima di HttpProxyMiddleware, che è a 750. Non garantisce la rotazione. Un retry riceve un proxy nuovo solo se il selettore riconosce la richiesta retry copiata e sovrascrive il precedente valore meta["proxy"].
Come gestisco automaticamente i proxy morti in Scrapy?
Costruisci un middleware che tenga traccia del numero di fallimenti per proxy in process_response e process_exception, rimuova i proxy dal pool attivo dopo una soglia di fallimento e li reinserisca dopo un periodo di raffreddamento invece di bannarli in modo permanente.
Posso usare Scrapy con proxy SOCKS5?
L’HttpxDownloadHandler sperimentale di Scrapy 2.17 documenta il supporto SOCKS5 quando è installato httpx[socks]. Il download handler HTTP/1.1 predefinito non supporta proxy SOCKS. Blocca handler e versione e fai un test di integrazione prima di considerare questo percorso pronto per la produzione.
Quanto può far risparmiare davvero il pattern proxy-on-retry sui costi dei proxy? Non esiste una percentuale portabile. Misura la quota di richieste autorizzate che restituiscono contenuto valido direttamente, i byte inviati tramite ciascun livello proxy, i retry per ogni record andato a buon fine e la latenza aggiunta. La riduzione osservata dei byte via proxy è il tuo risparmio; se l’accesso diretto non è autorizzato o non è valido, non usare questo pattern.


