Jeśli budujesz scrapery w Go, prawdopodobnie znasz Colly — najpopularniejszy framework do web scrapingu w tym języku. Colly jest szybki, asynchroniczny i idiomatyczny, ale bez odpowiedniej rotacji proxy szybko napotkasz blokad IP, CAPTCHA i bany. W tym przewodniku pokazujemy, jak zaimplementować rotację proxy w Colly używając residential proxy, przełącznika RoundRobinProxySwitcher oraz własnych funkcji proxy z geo-targetowaniem.
Uwaga prawna: Scrapowanie danych publicznych jest ogólnie legalne, ale musisz przestrzegać robots.txt (RFC 9309), warunków usług (ToS) witryny oraz przepisów takich jak GDPR i CFAA. Ten artykuł dotyczy wyłącznie danych publicznie dostępnych. Nie zachęcamy do omijania zabezpieczeń ani naruszania praw własności.
Rotacja proxy w Colly — dlaczego jest niezbędna
Colly wysyła żądania HTTP asynchronicznie, wykorzystując goroutines i kanały Go. Domyślnie wszystkie żądania wychodzą z jednego adresu IP. Jeśli wykonasz 1000 żądań do tej samej domeny w ciągu minuty, większość nowoczesnych stron wykryje ten wzorzec i zablokuje Twój adres IP — często w ciągu pierwszych 200 żądań.
Rotacja proxy rozwiązuje ten problem, dystrybuując żądania przez wiele adresów IP. Każde żądanie może wychodzić z innego IP, co utrudnia wykrycie wzorca. W Colly rotacja proxy realizowana jest na poziomie http.Request — framework pozwala na podmianę URL proxy dla każdego żądania przez mechanizm SetProxyFunc.
Dlaczego residential proxy są lepsze niż datacenter dla trudnych celów? Strony e-commerce, platformy społecznościowe i wyszukiwarki mają zaawansowane systemy anty-bot, które flagują ranges IP z centrów danych. Residential IP należą do rzeczywistych dostawców internetowych (ISP), co czyni je trudniejszymi do odróżnienia od ruchu organicznego.
Model Collector w Colly — OnRequest, OnHTML, OnError
Colly opiera się na wzorcu Collector — obiekcie konfigurowanym przez callbacki. Najważniejsze z nich to:
- OnRequest — wywoływany przed wysłaniem każdego żądania. Idealne miejsce do ustawiania nagłówków, modyfikacji URL lub logowania.
- OnHTML — wywoływany po pobraniu strony, gdy HTML jest parsowany przez goquery. Pozwala na selektor-based traversal DOM.
- OnError — wywoływany, gdy żądanie kończy się błędem. Tu implementujesz logikę retry.
- OnResponse — wywoływany po otrzymaniu pełnej odpowiedzi, przed parsowaniem HTML.
Tryb asynchroniczny (domyślny w Colly) oznacza, że żądania są kolejkowane i wykonywane równolegle z ograniczeniem współbieżności ustawianym przez colly.AsyncOptions.Parallelism. To kluczowe dla wydajności, ale zwiększa ryzyko blokad — dlatego rotacja proxy jest tu krytyczna.
Przełącznik proxy w Colly — RoundRobinProxySwitcher i SetProxyFunc
Colly oferuje wbudowany proxy.RoundRobinProxySwitcher, który przyjmuje listę URL-i proxy i rotuje je cyklicznie. Oto podstawowy przykład z ProxyHat:
package main
import (
"log"
"github.com/gocolly/colly/v2"
"github.com/gocolly/colly/v2/proxy"
)
func main() {
c := colly.NewCollector()
// Lista endpointów ProxyHat (HTTP, port 8080)
proxies := []*url.URL{
url.Parse("http://user-country-US:pass@gate.proxyhat.com:8080"),
url.Parse("http://user-country-DE:pass@gate.proxyhat.com:8080"),
url.Parse("http://user-country-GB:pass@gate.proxyhat.com:8080"),
url.Parse("http://user-country-FR:pass@gate.proxyhat.com:8080"),
}
// RoundRobinProxySwitcher rotuje proxy cyklicznie
switcher, err := proxy.RoundRobinProxySwitcher(proxies...)
if err != nil {
log.Fatal(err)
}
c.SetProxyFunc(switcher)
c.OnHTML("title", func(e *colly.HTMLElement) {
log.Printf("Tytuł: %s | IP proxy: %s", e.Text, e.Request.ProxyURL)
})
c.Visit("https://httpbin.org/ip")
c.Wait()
}
SetProxyFunc przyjmuje funkcję typu func(*http.Request) (*url.URL, error). Możesz napisać własną funkcję zamiast RoundRobinProxySwitcher, aby implementować logikę rotacji dostosowaną do Twoich potrzeb — np. wybór kraju na podstawie docelowego URL albo sticky sessions.
Rotacyjne proxy z geo-targetowaniem — username per request
ProxyHat pozwala na geo-targetowanie i kontrolę sesji przez nazwę użytkownika. Format to:
user-country-DE— proxy z Niemiecuser-country-DE-city-berlin— proxy z Berlinauser-session-abc123— sticky session (ten sam IP dla wielu żądań)user-country-US-session-xyz789— kombinacja kraju i sesji
W Colly możesz dynamicznie generować URL proxy dla każdego żądania, korzystając z własnej funkcji w SetProxyFunc. Oto przykład, który rotuje kraje i przypisuje unikalne sesje:
package main
import (
"crypto/rand"
"encoding/hex"
"fmt"
"math/rand/v2"
"net/http"
"net/url"
"github.com/gocolly/colly/v2"
)
var countries = []string{"US", "DE", "GB", "FR", "PL", "NL", "SE", "CA"}
func randomSession() string {
b := make([]byte, 6)
rand.Read(b)
return hex.EncodeToString(b)
}
func proxyFunc(r *http.Request) (*url.URL, error) {
country := countries[rand.IntN(len(countries))]
session := randomSession()
proxyURL := fmt.Sprintf(
"http://user-country-%s-session-%s:pass@gate.proxyhat.com:8080",
country, session,
)
return url.Parse(proxyURL)
}
func main() {
c := colly.NewCollector()
c.SetProxyFunc(proxyFunc)
c.OnHTML("h1", func(e *colly.HTMLElement) {
fmt.Printf("Proxy: %s\n", e.Request.ProxyURL)
})
c.OnError(func(r *colly.Response, err error) {
fmt.Printf("Błąd: %v (status: %d)\n", err, r.StatusCode)
})
c.Visit("https://httpbin.org/ip")
c.Wait()
}
Ten wzorzec daje pełną kontrolę: każde żądanie wychodzi z innego kraju i innej sesji, co maksymalizuje dywersyfikację IP. Jeśli potrzebujesz sticky session (np. do logowania i utrzymania sesji), użyj tego samego identyfikatora sesji dla całego przepływu.
SOCKS5 jest również obsługiwany — wystarczy zmienić schemat URL i port:
proxyURL := "socks5://user-country-US:pass@gate.proxyhat.com:1080"
Kompletny przykład Go — Collector z residential proxy i Limit()
Poniżej znajduje się kompletny, produkcyjny przykład łączący rotację proxy, limitowanie współbieżności, opóźnienia i logikę retry przez c.Clone():
package main
import (
"crypto/rand"
"encoding/hex"
"fmt"
"math/rand/v2"
"net/http"
"net/url"
"time"
"github.com/gocolly/colly/v2"
"github.com/gocolly/colly/v2/debug"
)
var countries = []string{"US", "DE", "GB", "FR", "PL", "NL"}
func randomSession() string {
b := make([]byte, 6)
rand.Read(b)
return hex.EncodeToString(b)
}
func residentialProxyFunc(r *http.Request) (*url.URL, error) {
country := countries[rand.IntN(len(countries))]
session := randomSession()
u := fmt.Sprintf(
"http://user-country-%s-session-%s:YOUR_PASSWORD@gate.proxyhat.com:8080",
country, session,
)
return url.Parse(u)
}
func main() {
c := colly.NewCollector(
colly.MaxDepth(2),
colly.UserAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64)"),
)
// Konfiguracja proxy
c.SetProxyFunc(residentialProxyFunc)
// Limitowanie: max 5 równoległych żądań, losowe opóźnienie 1-3s
c.Limit(&colly.LimitRule{
DomainGlob: "*",
Parallelism: 5,
Delay: 2 * time.Second,
RandomDelay: 1 * time.Second,
})
// Włącz tryb asynchroniczny
c.Async = true
var visited int
c.OnHTML("a[href]", func(e *colly.HTMLElement) {
link := e.Attr("href")
e.Request.Visit(link)
})
c.OnResponse(func(r *colly.Response) {
visited++
fmt.Printf("[%d] %s — status: %d, proxy: %s\n",
visited, r.Request.URL, r.StatusCode, r.Request.ProxyURL)
})
c.OnError(func(r *colly.Response, err error) {
fmt.Printf("Błąd: %v, status: %d, URL: %s\n", err, r.StatusCode, r.Request.URL)
// Retry przez klonowanie collector z nowym proxy
if r.StatusCode == 403 || r.StatusCode == 429 {
clone := r.Request.Ctx.Colly.Clone()
clone.SetProxyFunc(residentialProxyFunc)
clone.Visit(r.Request.URL.String())
}
})
c.Visit("https://example.com")
c.Wait()
}
Kluczowe elementy tego przykładu:
- LimitRule z
Parallelism: 5iDelay: 2s+RandomDelay: 1szapobiega zalananiu serwera. - OnError z retry przez
c.Clone()tworzy nowy collector z nowym proxy dla nieudanych żądań (403/429). - MaxDepth(2) ogranicza głębokość crawlowania.
- Async = true włącza asynchroniczne wykonywanie żądań.
Wzorce produkcyjne — skalowanie, retries, distributed scraping
Własny Transport z konfiguracją TLS
Dla trudnych celów, które wymagają specyficznej konfiguracji TLS (np. niestandardowe cipher suites), możesz podmienić http.Transport w collectorze:
import (
"crypto/tls"
"net/http"
)
c := colly.NewCollector()
c.WithTransport(&http.Transport{
TLSClientConfig: &tls.Config{
InsecureSkipVerify: false,
MinVersion: tls.VersionTLS12,
},
MaxIdleConns: 100,
MaxIdleConnsPerHost: 10,
IdleConnTimeout: 30 * time.Second,
})
Distributed scraping z redis storage
Colly wspiera rozproszone crawlowanie przez kolejki współdzielone. Backend redis pozwala wielu instancjom na współdzielenie stanu odwiedzonych URL-i:
import (
"github.com/gocolly/colly/v2"
"github.com/gocolly/redis"
)
c := colly.NewCollector()
storage := &redis.Storage{
Address: "redis://localhost:6379",
Prefix: "colly_scraper_",
Client: nil,
}
c.SetStorage(storage)
W połączeniu z rotacyjnymi residential proxy z ProxyHat, możesz uruchomić wiele instancji scrapera w kontenerach Docker, każda z własnym zestawem sesji proxy. Skonsultuj dokumentację ProxyHat, aby dowiedzieć się więcej o dostępnych krajach i konfiguracji.
Porównanie typów proxy dla Colly
| Cecha | Residential | Datacenter | Mobile |
|---|---|---|---|
| Wykrywalność przez anty-bot | Niska | Wysoka | Bardzo niska |
| Prędkość | Średnia (~100-300 ms) | Wysoka (<50 ms) | Niska (~300-800 ms) |
| Średni | Niski | Wysoki | |
| Najlepsze zastosowanie | E-commerce, SERP, social media | Proste API, dane publiczne | App mobile, bardzo trudne cele |
| Limit równoległych sesji | Wysoki (100+) | Średni | Niski |
Dla większości zastosowań web scrapingu w Colly residential proxy oferują najlepszy stosunek wydajności do wykrywalności. Sprawdź dostępne lokalizacje ProxyHat, aby zaplanować strategię geo-targetowania.
Częste błędy i przypadki brzegowe
1. Brak obsługi błędów proxy
Jeśli proxy zwraca błąd połączenia, Colly wywoła OnError. Bez logiki retry tracisz żądanie. Zawsze implementuj retry z nowym proxy przez c.Clone() lub kolejkowanie ponownych prób.
2. Zbyt wysoka współbieżność
Parallelism: 50 bez rotacji proxy to gwarancja bana. Utrzymuj współbieżność na poziomie 5-10 równoległych żądań na domenę z rotacją IP.
3. Ignorowanie robots.txt
Colly domyślnie nie sprawdza robots.txt. Możesz włączyć to przez colly.IgnoreRobotsTxt(false). Zawsze przestrzegaj RFC 9309 i zasady robots.txt.
4. Brak timeoutów
Bez timeoutów scraper może zawiesić się na martwym proxy. Ustaw c.SetRequestTimeout(30 * time.Second), aby uniknąć nieskończonego czekania.
5. Niespójne nagłówki
Każde żądanie z innym IP, ale z tym samym User-Agent, może zostać wykryte. Używaj realistycznych nagłówków i rotuj je razem z proxy.
Kiedy NIE używać Colly
Colly jest świetne dla stron serwerowo renderowanych (SSR), gdzie HTML jest dostępny w odpowiedzi HTTP. Jeśli strona wymaga JavaScript do renderowania treści (SPA oparte na React, Vue, Angular), Colly nie wykona JS i nie zobisz dynamicznej treści. W takich przypadkach rozważ:
- chromedp — sterowanie Chrome w Go przez DevTools Protocol.
- Playwright — przez bindings Go.
- Rod — higher-level wrapper dla chromedp.
Nawet w tych przypadkach rotacja proxy jest konieczna — większość browser-automation frameworks wspiera konfigurację proxy na poziomie launch options.
Konfiguracja ProxyHat dla Colly
ProxyHat oferuje residential, mobile i datacenter proxy z geo-targetowaniem na poziomie kraju i miasta. Konfiguracja w Colly jest prosta — wszystkie parametry przekazywane są w nazwie użytkownika. Szczegóły znajdziesz w dokumentacji ProxyHat.
Dla SERP tracking i monitorowania wyników wyszukiwania, residential proxy z ProxyHat zapewniają 99.9% uptime i tysiące unikalnych IP. Sprawdź naszą stronę SERP tracking oraz web scraping, aby dowiedzieć się więcej o zastosowaniach. Cennik znajdziesz na stronie ProxyHat pricing.
Najważniejsze wnioski
- Rotacja proxy jest obowiązkowa dla jakiegokolwiek scrapera powyżej ~100 żądań do jednej domeny.
- RoundRobinProxySwitcher jest prosty, ale własna funkcja w
SetProxyFuncdaje pełną kontrolę nad geo-targetowaniem i sesjami.- Residential proxy są najlepsze dla trudnych celów — datacenter IP są łatwo flagowane przez systemy anty-bot.
- LimitRule z
ParallelismiRandomDelayjest kluczowy dla unikania blokad.- Retry przez c.Clone() pozwala na ponowne próby z nowym proxy przy błędach 403/429.
- Redis storage umożliwia distributed scraping z współdzielonym stanem odwiedzonych URL-i.
- Colly nie renderuje JS — dla SPA używaj chromedp lub Playwright.
- Etyka: przestrzegaj robots.txt, ToS i GDPR. Scrapuj tylko dane publiczne.
Rotacja proxy w Colly to nie dodatek — to fundament produkcyjnego scrapera. Z residential proxy ProxyHat, idiomatycznym SetProxyFunc i wzorcami opisanymi w tym artykule, możesz budować scrapery, które działają niezawodnie na dużą skalę.






