Se você está construindo scrapers em Go com Colly e está enfrentando bloqueios de IP, proxies rotativos em Colly são a extensão natural do seu collector. Este guia mostra como usar a API idiomática de proxy do Colly — proxy.RoundRobinProxySwitcher e c.SetProxyFunc— para integrar proxies residenciais da ProxyHat, com rotação de país, cidade e sessão por requisição.
Antes de mergulharmos: este artigo cobre técnicas para coletar dados públicos. Raspar dados atrás de login ou violar Termos de Serviço pode configurar violação do CFAA nos EUA ou processar dados pessoais sob a GDPR na Europa. Respeite robots.txt, limite taxas de requisição e consulte a jurisprudência aplicável.
Como Funcionam os Proxies Rotativos em Colly
Colly é um framework de scraping para Go baseado em callbacks. O Collector é a unidade central: você registra handlers como OnRequest, OnHTML e OnError, dispara visitas com c.Visit(), e o framework gerencia o ciclo HTTP. Por padrão, o collector usa o http.DefaultTransport do Go, sem proxy.
A rotação de proxies entra como uma função de proxy que o Colly chama antes de cada requisição. O signature é:
type ProxyFunc func(*http.Request) (*url.URL, error)
Se essa função retorna uma URL de proxy diferente a cada chamada, você tem rotação automática. O Colly oferece proxy.RoundRobinProxySwitcher pronto para uso, mas você pode — e deve, em produção — escrever a sua própria.
O modelo é assíncrono por natureza: c.Visit() retorna imediatamente e o Colly processa a resposta em goroutines internas. Isso significa que a função de proxy é chamada de múltiplas goroutines concorrentemente — seu código precisa ser thread-safe.
O Modelo de Collector do Colly
O collector expõe três categorias de callbacks:
- OnRequest(func(*colly.Request)) — chamado antes da requisição sair; ideal para setar headers, User-Agent e cookies.
- OnHTML(selector string, func(*colly.HTMLElement)) — chamado quando o seletor CSS encontra elementos; usa goquery por baixo para traversal de DOM.
- OnError(func(*colly.Response, error)) — chamado em falhas; aqui você implementa retry lógico.
O HTMLElement do callback OnHTML é um wrapper sobre goquery, então você tem acesso a e.DOM.Find(...), e.Attr(), e.Text() e e.ForEach() com a mesma API do jQuery. Isso torna a extração concisa:
c.OnHTML("div.result h3", func(e *colly.HTMLElement) {
fmt.Println(e.Text)
e.ForEach("a", func(_ int, a *colly.HTMLElement) {
fmt.Println(a.Attr("href"))
})
})
O modo assíncrono é controlado por c.Async = true (padrão false). Em assíncrono, você precisa de c.Wait() ao final para bloquear até todas as goroutines terminarem.
Superfície Idiomática de Proxy no Colly
O Colly oferece duas formas de configurar proxies. A primeira é o RoundRobinProxySwitcher, que distribui requisições em round-robin entre uma lista fixa de URLs de proxy:
import "github.com/gocolly/colly/v2/proxy"
switcher, err := proxy.RoundRobinProxySwitcher(
"http://user:pass@gate.proxyhat.com:8080",
"http://user-country-DE:pass@gate.proxyhat.com:8080",
"http://user-country-US:pass@gate.proxyhat.com:8080",
)
if err != nil {
log.Fatal(err)
}
c.SetProxyFunc(switcher)
A segunda — mais flexível — é escrever sua própria ProxyFunc. Isso permite rotação dinâmica, geo-targeting por requisição, sessões sticky e lógica condicional baseada no domínio alvo:
func proxyHatSwitcher(req *http.Request) (*url.URL, error) {
// Rotação de país + sessão sticky por domínio
country := pickCountry(req.URL.Hostname())
session := fmt.Sprintf("sess-%d", time.Now().UnixNano()%10000)
user := fmt.Sprintf("user-country-%s-session-%s", country, session)
proxyURL := fmt.Sprintf("http://%s:pass@gate.proxyhat.com:8080", user)
return url.Parse(proxyURL)
}
c.SetProxyFunc(proxyHatSwitcher)
O Colly suporta esquemas http, https e socks5 nativamente. Para SOCKS5 com a ProxyHat, basta usar a porta 1080:
proxyURL := "socks5://user:pass@gate.proxyhat.com:1080"
Por Que Proxies Residenciais para Alvos Difíceis
Proxies datacenter são bloqueados rapidamente por anti-bot systems como Cloudflare, Datadome e PerimeterX, que mantêm listas de ASN de datacenter. Proxies residenciais usam IPs atribuídos a ISPs reais, tornando-os indistinguíveis de tráfego orgânico. Para alvos com proteção agressiva — e-commerce, SERPs, redes sociais — residenciais são obrigatórios.
A ProxyHat permite geo-targeting granular via flags no username. O formato é:
user-country-DE:pass— IP alemão aleatóriouser-country-DE-city-berlin:pass— IP de Berlimuser-session-abc123:pass— sessão sticky (mesmo IP por toda a sessão)user-country-US-session-abc123:pass— país + sessão combinados
Combinando isso com sua ProxyFunc, você pode garantir que cada requisição saia de um IP diferente, ou manter a mesma sessão para fluxos de login multi-step.
Exemplo Runnable: Collector com Rotação Residencial
Aqui está um exemplo completo de scraper Colly com rotação de proxies residenciais, limites de taxa e tratamento de erros:
package main
import (
"fmt"
"log"
"math/rand"
"net/http"
"net/url"
"time"
"github.com/gocolly/colly/v2"
"github.com/gocolly/colly/v2/proxy"
)
var countries = []string{"US", "DE", "GB", "FR", "BR", "JP"}
func pickCountry() string {
return countries[rand.Intn(len(countries))]
}
func residentialSwitcher(req *http.Request) (*url.URL, error) {
country := pickCountry()
session := fmt.Sprintf("sess-%d", rand.Intn(100000))
user := fmt.Sprintf("user-country-%s-session-%s", country, session)
proxyStr := fmt.Sprintf("http://%s:PASSWORD@gate.proxyhat.com:8080", user)
return url.Parse(proxyStr)
}
func main() {
rand.Seed(time.Now().UnixNano())
c := colly.NewCollector(
colly.MaxDepth(2),
colly.UserAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64)"),
)
// Rotação de proxy residencial
if err := c.SetProxyFunc(residentialSwitcher); err != nil {
log.Fatal(err)
}
// Limites de taxa: 2 requisições/segundo, paralelismo 4
c.Limit(&colly.LimitRule{
DomainGlob: "*",
Parallelism: 4,
Delay: 500 * time.Millisecond,
RandomDelay: 500 * time.Millisecond,
})
c.OnRequest(func(r *colly.Request) {
r.Headers.Set("Accept-Language", "en-US,en;q=0.9")
fmt.Printf("Visitando %s via proxy\n", r.URL.String())
})
c.OnHTML("h1", func(e *colly.HTMLElement) {
fmt.Printf("Título: %s\n", e.Text)
})
c.OnError(func(r *colly.Response, err error) {
fmt.Printf("Erro em %s: %v (status %d)\n", r.Request.URL, err, r.StatusCode)
// Retry com clone
if r.StatusCode == 403 || r.StatusCode == 429 {
time.Sleep(2 * time.Second)
r.Request.Retry()
}
})
c.OnScraped(func(r *colly.Response) {
r.Visit("https://example.com/page2")
})
c.Visit("https://example.com")
c.Wait()
}
Este exemplo cobre os três pilares: rotação de proxy por requisição, controle de taxa via Limit() e retry automático em 403/429. O RandomDelay de 500ms adiciona jitter para evitar padrões detectáveis.
Switcher Customizado com Lista de Endpoints
Para controle mais fino, você pode ler uma lista de configurações de proxy de um arquivo ou API e construir um switcher que combina round-robin com geo-targeting:
type proxyConfig struct {
Country string
City string
Session string
}
type smartSwitcher struct {
configs []proxyConfig
idx uint32
}
func (s *smartSwitcher) GetProxy(req *http.Request) (*url.URL, error) {
n := atomic.AddUint32(&s.idx, 1)
cfg := s.configs[int(n)%len(s.configs)]
user := fmt.Sprintf("user-country-%s", cfg.Country)
if cfg.City != "" {
user += fmt.Sprintf("-city-%s", cfg.City)
}
if cfg.Session != "" {
user += fmt.Sprintf("-session-%s", cfg.Session)
}
proxyStr := fmt.Sprintf("http://%s:PASSWORD@gate.proxyhat.com:8080", user)
return url.Parse(proxyStr)
}
// Uso:
switcher := &smartSwitcher{configs: loadConfigs()}
c.SetProxyFunc(switcher.GetProxy)
Usar atomic.AddUint32 garante thread-safety entre goroutines concorrentes — algo essencial quando Parallelism > 1.
Padrões de Produção para Scraping em Escala
Retries com c.Clone()
O método c.Clone() cria uma cópia do collector com os mesmos callbacks e configurações. Isso é útil para isolamento de retry — você pode clonar o collector com um proxy diferente e re-tentar sem afetar o estado do collector principal:
c.OnError(func(r *colly.Response, err error) {
if r.StatusCode >= 500 || r.StatusCode == 429 {
clone := c.Clone()
// O clone herda a ProxyFunc, mas você pode sobrescrever
time.Sleep(time.Duration(r.StatusCode-400) * time.Second)
clone.Visit(r.Request.URL.String())
}
})
RandomDelay e Parallelism
O LimitRule controla três dimensões de taxa:
- Parallelism — número máximo de requisições concorrentes por domínio.
- Delay — espera fixa entre requisições ao mesmo domínio.
- RandomDelay — jitter aleatório adicionado ao Delay.
Para scraping respeitoso, use Parallelism: 2-5, Delay: 1s e RandomDelay: 2s. Isso resulta em 1 requisição a cada 1-3 segundos por domínio — abaixo do radar da maioria dos anti-bots.
Transport TLS Customizado
Para alvos que fazem fingerprinting de TLS (JA3), você pode customizar o http.Transport do collector:
c.WithTransport(&http.Transport{
TLSClientConfig: &tls.Config{
MinVersion: tls.VersionTLS12,
MaxVersion: tls.VersionTLS13,
InsecureSkipVerify: false,
CipherSuites: []uint16{
tls.TLS_AES_128_GCM_SHA256,
tls.TLS_CHACHA20_POLY1305_SHA256,
},
},
Proxy: http.ProxyFromEnvironment,
DialContext: (&net.Dialer{
Timeout: 30 * time.Second,
KeepAlive: 30 * time.Second,
}).DialContext,
})
Para fingerprinting mais avançado, considere usar uTLS que permite imitar o ClientHello de navegadores reais.
Scraping Distribuído com Redis
Para distribuir scraping entre múltiplas máquinas, o Colly oferece backends de storage. O redisstorage permite que múltiplas instâncias compartilhem a fila de URLs visitadas e cookies:
import "github.com/gocolly/redisstorage"
storage := &redisstorage.Storage{
Address: "redis://localhost:6379",
Prefix: "colly_scraper",
}
c.SetStorage(storage)
// Deduplicação automática: URLs visitados não são re-visitados
Com 3-5 instâncias, cada uma rodando com Parallelism: 4, você pode sustentar 1500+ requisições por minuto sem sobrecarregar um único host. O Redis garante que nenhuma instância repita trabalho já feito por outra.
Quando NÃO Usar Colly
Colly é excelente para HTML estático e páginas server-rendered. Mas se o alvo é uma SPA (Single Page Application) que renderiza conteúdo via JavaScript — React, Vue, Angular — o Colly não executa JS. Nesses casos, você precisa de um browser headless:
- chromedp — controle Chrome via DevTools Protocol em Go, nativo.
- rod — alternativa mais simples ao chromedp, com API fluente.
- Playwright Go — porta do Playwright para Go, com suporte a Chromium/Firefox/WebKit.
Com browsers headless, você ainda pode usar proxies residenciais da ProxyHat via flag --proxy-server do Chrome ou configuração do Playwright. A diferença é que o browser resolve JavaScript antes da extração.
Um sinal claro de que você precisa de um browser: o HTML retornado pelo Colly não contém o conteúdo que você vê no navegador — apenas um <div id="root"></div> vazio.
Comparação: Tipos de Proxy no Colly
| Característica | Datacenter | Residencial | Mobile |
|---|---|---|---|
| Velocidade | ~50ms | ~200-800ms | ~500-2000ms |
| Taxa de bloqueio | Alta (40-60%) | Baixa (5-15%) | Muito baixa (<5%) |
| Custo | $$$ | $$$$ | $$$$$ |
| Ideal para | Scraping leve, APIs públicas | Scraping de SERPs, e-commerce | Apps mobile, redes sociais |
| Geo-targeting | Limitado | País + cidade | País + cidade + operadora |
Para a maioria dos casos de web scraping e SERP tracking, proxies residenciais oferecem o melhor equilíbrio custo-benefício. Confira as localizações disponíveis e o plano de preços da ProxyHat.
Considerações Éticas e Legais
Scraping de dados públicos é geralmente legal, mas o cenário é complexo:
- CFAA (EUA) — acessar sistemas sem autorização pode configurar crime federal. Evite alvos que exigem bypass de autenticação.
- GDPR (UE) — dados pessoais são protegidos. Se você coleta emails, nomes ou IPs, precisa de base legal.
- robots.txt — respeite. O Colly não lê robots.txt automaticamente; você deve implementar isso.
- Rate limiting — não sobrecarregue o servidor alvo. 1-5 req/segundo é razoável.
Para uma discussão mais profunda sobre o framework, consulte a documentação da ProxyHat.
Principais Conclusões
Key Takeaways:
- Use
c.SetProxyFunc()com umaProxyFunccustomizada para rotação dinâmica de proxies residenciais — é mais flexível queRoundRobinProxySwitcher.- Geo-targeting e sessões sticky são controlados via flags no username:
user-country-DE-city-berlin-session-abc123.- Sempre configure
Limit()comParallelism,DelayeRandomDelaypara evitar bloqueios e ser respeitoso.- Use
c.Clone()para retries isolados eredisstoragepara scraping distribuído entre múltiplas máquinas.- Colly não executa JavaScript — para SPAs, use chromedp ou Playwright Go com proxies residenciais.
- Proxies residenciais oferecem 85-95% de taxa de sucesso contra 40-60% de datacenter em alvos protegidos.
FAQ
O que são Proxies Rotativos em Colly?
Proxies rotativos em Colly são a prática de usar a API SetProxyFunc ou RoundRobinProxySwitcher do framework para enviar cada requisição HTTP por um proxy diferente. O Colly chama a função de proxy antes de cada requisição, permitindo que você retorne uma URL de proxy diferente — com IP, país ou sessão distintos — a cada chamada. Isso distribui o tráfego entre múltiplos IPs, evitando bloqueios por rate limiting ou detecção de padrões.
Por que proxies rotativos importam para usuários de proxy no Colly?
Sem rotação, todas as requisições saem do mesmo IP, que é rapidamente bloqueado por sistemas anti-bot após 50-200 requisições. Com rotação residencial, cada requisição pode sair de um IP de ISP diferente, tornando o tráfego indistinguível de visitantes orgânicos. Isso aumenta a taxa de sucesso de 40-60% (datacenter sem rotação) para 85-95% (residencial com rotação), especialmente em alvos como SERPs, e-commerce e redes sociais com proteção agressiva.
Qual tipo de proxy funciona melhor para rotação em Colly?
Proxies residenciais são a melhor escolha para a maioria dos casos de scraping em Colly. Eles usam IPs atribuídos a ISPs reais, passando por verificações de ASN que bloqueiam datacenter. Para alvos extremamente protegidos (apps mobile, redes sociais com detecção de device fingerprint), proxies mobile oferecem a maior taxa de sucesso, mas com custo e latência maiores. Datacenter é adequado apenas para APIs públicas e sites sem proteção anti-bot.
Como evitar bloqueios ao implementar proxies rotativos em Colly?
Combine quatro estratégias: (1) rotação de proxy residencial com SetProxyFunc mudando país/sessão por requisição; (2) limites de taxa via c.Limit() com Parallelism: 4, Delay: 1s e RandomDelay: 2s; (3) User-Agent e headers realistas via OnRequest; (4) retries com backoff exponencial em OnError para status 429/403. Respeite robots.txt e não exceda 5 requisições por segundo por domínio.






