Proxy Rotanti in Colly: perché servono e come configurarli
Se stai costruendo uno scraper in Go con Colly, prima o poi ti scontri con i limiti di frequenza dei siti target. Un singolo IP che invia centinaia di richieste al minuto viene bloccato rapidamente — spesso dopo sole 100–200 richieste su endpoint protetti. I proxy rotanti in Colly risolvono il problema distribuendo il traffico su un pool di IP, idealmente residenziali, in modo che ogni richiesta sembri provenire da un utente diverso.
Prima di entrare nei dettagli tecnici, una precisazione etica e legale: raccogli solo dati pubblicamente accessibili, rispetta il file robots.txt, i termini di servizio e le normative come il GDPR e il CFAA. Lo scraping di dati personali o dietro autenticazione senza consenso è illegale in molte giurisdizioni. Questa guida presuppone che tu operi su dati pubblici e in conformità con le normative applicabili.
Colly è il framework di scraping de facto per Go, basato su net/http e goquery per il traversal del DOM. Supporta callback asincrone, limiti di parallelismo, storage backend (Redis, in-memory) e — aspetto cruciale — un'interfaccia nativa per il proxy switching. In questa guida vedrai come usarla correttamente, senza hack, integrando i proxy residenziali di ProxyHat.
Il modello Collector di Colly: callback, async e goquery
Il cuore di Colly è il Collector, che orchesta il ciclo di vita di ogni richiesta HTTP. I punti di estensione principali sono tre callback:
- OnRequest: eseguito prima che la richiesta venga inviata. È qui che puoi modificare header, User-Agent, cookie e — in alcuni casi — il proxy per-request.
- OnHTML: eseguito quando il body HTML è disponibile. Usa selettori CSS goquery per estrarre dati e fare scraping ricorsivo con
c.Visit(). - OnError: eseguito in caso di errore HTTP o di parsing. È il posto giusto per logica di retry, backoff e cambio proxy.
Colly opera in modalità asincrona per default: ogni c.Visit() viene accodato e le richieste vengono eseguite in goroutine separate, regolate da Limit(). Questo significa che il proxy switching deve essere thread-safe — un dettaglio che vedremo nella sezione sull'implementazione.
Il traversal del DOM è gestito da goquery, un port di jQuery in Go. Le API sono familiari: Find(), Each(), Attr(), Text(). Non c'è motore JavaScript: se il sito target è una SPA che renderizza tutto lato client, Colly non basta e serve un browser headless (vedi la sezione finale).
La superficie idiomatica dei proxy: SetProxyFunc e RoundRobinProxySwitcher
Colly espone due livelli per gestire i proxy:
- proxy.RoundRobinProxySwitcher(urls ...string): uno switcher round-robin predefinito. Gli passi una lista di URL proxy e Colly li cicla in ordine. Semplice, ma limitato — non supporta logiche di rotazione avanzate.
- c.SetProxyFunc(func(*http.Request) (*url.URL, error)): il punto di estensione vero. Gli passi una funzione custom che riceve la richiesta e restituisce l'URL del proxy da usare. Qui puoi implementare qualsiasi strategia: round-robin, random, sticky session, geo-targeting per dominio.
La firma func(*http.Request) (*url.URL, error) è la stessa del campo ProxyURL di http.Transport in Go standard. Questo significa che il proxy switching in Colly è completamente compatibile con l'ecosistema net/http — puoi usare qualsiasi proxy che supporti i formati http://, https:// o socks5://.
Per ProxyHat, i formati sono:
# HTTP
http://USERNAME:PASSWORD@gate.proxyhat.com:8080
# SOCKS5
socks5://USERNAME:PASSWORD@gate.proxyhat.com:1080
# Geo-targeting (Germania, Berlino)
http://user-country-DE-city-berlin:pass@gate.proxyhat.com:8080
# Sessione sticky
http://user-session-abc123:pass@gate.proxyhat.com:8080
La rotazione avviene a livello di username: ogni combinazione di country, city e session produce un IP diverso. Non hai bisogno di gestire una pool di IP manualmente — ProxyHat lo fa per te.
Perché i proxy residenziali sono necessari per target difficili
I proxy datacenter sono veloci ed economici, ma i loro range IP sono noti e facilmente filtrabili. Servizi anti-bot come Cloudflare, Datadome e PerimeterX bloccano attivamente gli IP ASN datacenter con una precisione che spesso supera il 95% sulle richieste automatizzate.
I proxy residenziali, invece, usano IP assegnati a dispositivi reali tramite ISP. Per il sito target, il traffico appare identico a quello di un utente legittimo. Questo li rende essenziali per:
- SERP scraping (Google, Bing, Yandex)
- Price monitoring su e-commerce protetti
- Social media research
- Raccolta di dati per training di modelli AI
Con ProxyHat, la rotazione residenziale è trasparente: basta cambiare il parametro session nello username per ottenere un nuovo IP. Una sessione sticky mantiene lo stesso IP per tutta la durata della sessione — utile quando il sito target richiede login o carrello persistente.
Esempio Go: Collector con RoundRobinProxySwitcher residenziale
Vediamo un esempio completo e runnable. L'obiettivo: scraperare una lista di URL usando proxy residenziali con rotazione, limiti di parallelismo e retry.
package main
import (
"fmt"
"log"
"math/rand"
"net/url"
"sync/atomic"
"time"
"github.com/gocolly/colly/v2"
"github.com/gocolly/colly/v2/proxy"
)
// residentialSwitcher implementa una rotazione custom
// con geo-targeting e sessioni sticky per-request.
type residentialSwitcher struct {
idx uint64
countries []string
}
func (r *residentialSwitcher) getProxy(req *http.Request) (*url.URL, error) {
// Rotazione round-robin sui paesi
n := atomic.AddUint64(&r.idx, 1)
country := r.countries[n%uint64(len(r.countries))]
// Sessione unica per request: forza nuovo IP
session := fmt.Sprintf("sess-%d-%d", time.Now().UnixNano(), rand.Intn(99999))
proxyURL := fmt.Sprintf(
"http://user-country-%s-session-%s:PASSWORD@gate.proxyhat.com:8080",
country, session,
)
return url.Parse(proxyURL)
}
func main() {
c := colly.NewCollector(
colly.UserAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64)"),
colly.MaxDepth(2),
colly.AllowURLRevisit(),
)
// Switcher custom con geo-rotazione
switcher := &residentialSwitcher{
countries: []string{"DE", "US", "FR", "GB", "IT"},
}
c.SetProxyFunc(switcher.getProxy)
// Limiti: 5 richieste concorrenti, delay random 1-3s
c.Limit(&colly.LimitRule{
DomainGlob: "*",
Parallelism: 5,
Delay: 1 * time.Second,
RandomDelay: 2 * time.Second,
})
// Retry su errori 429/503
retries := 0
c.OnError(func(r *colly.Response, err error) {
if retries < 3 && (r.StatusCode == 429 || r.StatusCode == 503) {
retries++
time.Sleep(time.Duration(retries*2) * time.Second)
r.Request.Retry()
}
})
c.OnHTML("a[href]", func(e *colly.HTMLElement) {
link := e.Attr("href")
fmt.Printf("Link trovato: %s\n", link)
})
c.OnResponse(func(r *colly.Response) {
fmt.Printf("[%d] %s - %d bytes\n", r.StatusCode, r.Request.URL, len(r.Body))
})
urls := []string{
"https://example.com/page1",
"https://example.com/page2",
"https://example.com/page3",
}
for _, u := range urls {
c.Visit(u)
}
c.Wait()
}
Notare l'uso di atomic.AddUint64 per il contatore: è obbligatorio perché Colly esegue le richieste in goroutine concorrenti e un contatore non atomico causerebbe data race.
Per uno switcher più semplice, puoi usare proxy.RoundRobinProxySwitcher con una lista di URL pre-generati:
// Genera 10 URL proxy con sessioni diverse
var proxies []string
for i := 0; i < 10; i++ {
proxies = append(proxies,
fmt.Sprintf("http://user-session-rot%d:PASSWORD@gate.proxyhat.com:8080", i))
}
switcher, err := proxy.RoundRobinProxySwitcher(proxies...)
if err != nil {
log.Fatal(err)
}
c.SetProxyFunc(switcher)
Questo approccio è più semplice ma meno flessibile: non puoi cambiare paese dinamicamente o adattare la rotazione in base alla risposta del server.
Pattern di produzione: retry, delay, Transport e storage distribuito
Retry con c.Clone()
Colly offre c.Clone() per creare una copia di un Collector con la stessa configurazione. È utile per isolare i retry in un sub-collector con proxy diversi:
c.OnError(func(r *colly.Response, err error) {
if r.StatusCode == 403 {
// Clona il collector, cambia sessione proxy, riprova
clone := c.Clone()
clone.SetProxyFunc(func(req *http.Request) (*url.URL, error) {
session := fmt.Sprintf("retry-%d", time.Now().UnixNano())
return url.Parse(
fmt.Sprintf("http://user-session-%s:PASSWORD@gate.proxyhat.com:8080", session))
})
clone.Visit(r.Request.URL.String())
}
})
RandomDelay e Parallelism
Il metodo Limit() è fondamentale per evitare di saturare il target. Una configurazione equilibrata per scraping residenziale:
- Parallelism: 5–10 richieste concorrenti per dominio. Oltre 10, il rischio di CAPTCHA aumenta significativamente.
- Delay: 1 secondo base.
- RandomDelay: 2–3 secondi aggiuntivi. Il random delay è essenziale — pattern di traffico perfettamente regolari sono facilmente rilevabili come bot.
Custom Transport con TLS config
Per siti con TLS fingerprinting aggressivo, puoi personalizzare il Transport di Colly:
import (
"crypto/tls"
"net/http"
)
c.WithTransport(&http.Transport{
TLSClientConfig: &tls.Config{
InsecureSkipVerify: false,
MinVersion: tls.VersionTLS12,
MaxVersion: tls.VersionTLS13,
},
MaxIdleConns: 100,
IdleConnTimeout: 90 * time.Second,
TLSHandshakeTimeout: 10 * time.Second,
})
Evita InsecureSkipVerify: true in produzione: non risolve il TLS fingerprinting e apre vettori di attacco MITM.
Storage distribuito con Redis
Per scraping distribuito su più istanze (container, VM), Colly supporta backend di storage per condividere lo stato delle visite:
import "github.com/gocolly/colly/v2/storage"
// Redis backend per deduplicazione cross-istanza
storage := &storage.RedisStorage{
Address: "redis://localhost:6379",
Prefix: "colly_scraper",
}
c.SetStorage(storage)
Questo evita di rivisitare URL già processati da altre istanze. Per deployment containerizzato, puoi combinare Redis storage con un orchestratore come Kubernetes per scalare orizzontalmente.
Confronto: proxy residenziali vs datacenter vs mobile
| Caratteristica | Residenziali | Datacenter | Mobile |
|---|---|---|---|
| Success rate su target hard | 90–98% | 30–60% | 95–99% |
| Latenza media | 200–800ms | 50–200ms | 500–2000ms |
| Costo per GB | Medio | Basso | Alto |
| Rilevabilità | Bassa | Alta | Minima |
| Casi d'uso tipici | SERP, e-commerce, social | API pubbliche, testing | App mobile, geo-restricted |
Per il colly web scraping su target generici, i residenziali offrono il miglior rapporto costo/affidabilità. I mobile sono superiori per target estremamente protetti ma costano 3–5 volte di più.
Quando NON usare Colly (e cosa usare al suo posto)
Colly è eccellente per HTML statico e API JSON. Non è adatto per:
- SPA JavaScript-heavy: siti che renderizzano tutto con React/Vue/Angular. Colly non esegue JS. Per questi casi, usa playwright-go o chromedp, combinando il browser headless con i proxy di ProxyHat.
- Siti con challenge JS obbligatorie: se il target richiede l'esecuzione di un challenge script prima di servire contenuto, serve un browser vero.
- Streaming dati: Colly è request-response. Per WebSocket o SSE, usa
gorilla/websocketdirettamente.
Una strategia ibrida comune: usa Colly per la fase di discovery (trova gli URL), e un browser headless solo per le pagine che richiedono rendering JS.
Considerazioni etiche e legali
Lo scraping è uno strumento tecnico, ma l'uso che ne fai ha implicazioni legali. Alcuni punti fermi:
- Rispetta robots.txt: Colly ha un metodo
c.IgnoreRobotsTxt = false(default). Non disattivarlo alla leggera. - Non accedere a dati personali senza base legale (consenso, legittimo interesse). Il GDPR sanziona fino a 20 milioni di euro o il 4% del fatturato globale.
- Non sovraccaricare il target: rate limiting ragionevole è non solo etico, ma tecnicamente vantaggioso — riduce ban e CAPTCHA.
- Verifica i ToS: alcuni siti proibiscono esplicitamente lo scraping nei loro termini. Anche se i dati sono pubblici, violare i ToS può avere conseguenze legali.
ProxyHat fornisce l'infrastruttura, ma la responsabilità sull'uso è tua. Per approfondire i casi d'uso legittimi, consulta la pagina sulle use case di web scraping e sul SERP tracking.
Configurazione ProxyHat: checklist rapida
- Crea un account su ProxyHat e ottieni le credenziali.
- Verifica la connettività:
curl -x http://user:pass@gate.proxyhat.com:8080 https://httpbin.org/ip - Scegli il tipo di proxy: residenziali per target hard, datacenter per API pubbliche.
- Configura lo switcher in Colly con
SetProxyFunc. - Imposta
Limit()con parallelismo 5–10 e random delay 2–3s. - Aggiungi retry su 429/503 con backoff esponenziale.
- Monitora il success rate: se scende sotto l'80%, riduci il parallelismo o cambia pool di paesi.
Per la lista completa delle locazioni disponibili e per la documentazione tecnica, consulta le risorse ufficiali.
Key Takeaways
Punti chiave per i proxy rotanti in Colly:
- Usa
c.SetProxyFunccon una funzione custom per rotazione flessibile —RoundRobinProxySwitcherva bene per casi semplici.- I proxy residenziali sono necessari per target protetti: success rate 90–98% vs 30–60% dei datacenter.
- La rotazione ProxyHat avviene via username:
user-country-DE-session-abc123produce un IP unico.- Limiti di parallelismo (5–10) e random delay (2–3s) sono essenziali per evitare ban.
- Per SPA JS-heavy, Colly non basta — usa playwright-go o chromedp con gli stessi proxy.
- Retry con
c.Clone()e backoff esponenziale su 429/503. Storage Redis per scraping distribuito.
FAQ
Cosa sono i proxy rotanti in Colly?
I proxy rotanti in Colly sono una strategia in cui ogni richiesta HTTP viene instradata attraverso un IP proxy diverso, usando l'interfaccia SetProxyFunc del Collector. Questo distribuisce il traffico su un pool di IP, riducendo il rischio di ban e rate limiting. In Colly, la rotazione può essere round-robin (con proxy.RoundRobinProxySwitcher) o custom (con una funzione func(*http.Request) (*url.URL, error)).
Perché i proxy rotanti in Colly sono importanti?
I proxy rotanti sono importanti perché permettono di superare i limiti di frequenza imposti dai siti target. Un singolo IP che invia centinaia di richieste viene bloccato rapidamente — spesso dopo 100–200 richieste su endpoint protetti. Distribuendo il traffico su più IP residenziali, ogni richiesta appare come proveniente da un utente diverso, mantenendo un success rate del 90–98% anche su target difficili come SERP o e-commerce protetti.
Quale tipo di proxy funziona meglio in Colly?
I proxy residenziali sono la scelta migliore per la maggior parte dei casi d'uso di scraping con Colly. Offrono un success rate del 90–98% sui target hard, contro il 30–60% dei datacenter, perché usano IP assegnati a dispositivi reali tramite ISP. I proxy mobile sono ancora più difficili da rilevare (95–99%) ma costano 3–5 volte di più. I datacenter sono adatti solo per API pubbliche e testing, dove il blocco IP non è un problema.
Come evitare i blocchi con i proxy rotanti in Colly?
Per evitare blocchi: imposta Limit() con parallelismo 5–10 richieste concorrenti e random delay di 2–3 secondi; usa proxy residenziali con rotazione per-request (sessione unica nello username); implementa retry con backoff esponenziale su HTTP 429 e 503 usando c.Clone(); configura un User-Agent realistico; e rispetta il file robots.txt. Se il success rate scende sotto l'80%, riduci il parallelismo o amplia il pool di paesi.
Colly supporta SOCKS5 per i proxy rotanti?
Sì, Colly supporta SOCKS5 attraverso il formato socks5:// nell'URL del proxy. Con ProxyHat, puoi usare socks5://USERNAME:PASSWORD@gate.proxyhat.com:1080 nella funzione passata a SetProxyFunc. SOCKS5 è utile quando il target blocca il traffico HTTP CONNECT o quando hai bisogno di tunneling TCP completo. La rotazione funziona identicamente: basta cambiare il parametro session nello username.






