Go ekosisteminde web scraping yapmak istediğinizde Colly, en hızlı ve en çok benimsenen çerçevelerden biridir. Ancak hedef siteler Cloudflare, PerimeterX veya Datadome gibi anti-bot duvarlarına sahip olduğunda, tek bir IP'den binlerce istek göndermek dakikalar içinde engellenmenize yol açar. İşte Colly'de döner proxy konusunun kritik olduğu nokta burasıdır: Her istekte IP değiştirmek, rate limitlerini aşmak ve engellenmeden ölçeklenmek için temel bir gerekliliktir.
Bu rehber, Colly'nin collector modelini, proxy yüzeyini ve residential IP rotasyonunu üretim seviyesinde nasıl kullanacağınızı adım adım anlatır. Ayrıca ProxyHat'ın gate.proxyhat.com:8080 gateway'i ile nasıl entegre edileceğini gösteren çalıştırılabilir Go örnekleri içerir.
Yasal Uyarı: Bu rehber yalnızca herkese açık verilerin toplanması içindir. CFAA ve GDPR kapsamında, bir sitenin Hizmet Şartları'nı ihlal eden veya kişisel verileri izinsiz toplayan scraping faaliyetleri yasa dışı olabilir. Her zaman
robots.txtkurallarına ve sitenin rate limit politikalarına saygı gösterin.
Colly'de Döner Proxy: Temel Mekanizma
Colly, Go'nun net/http paketi üzerine inşa edilmiş, event-driven bir scraping çerçevesidir. Her HTTP isteği bir Collector üzerinden geçer ve proxy'ler SetProxyFunc metodu ile istek seviyesinde enjekte edilir. Bu, her istek için farklı bir çıkış IP'si kullanmanıza olanak tanır.
Colly'nin proxy sistemi iki temel bileşenden oluşur:
- Built-in RoundRobinProxySwitcher: Verilen proxy listesinde sırayla dolaşır.
- Custom proxy function:
func(*http.Request) (*url.URL, error)imzasına sahip herhangi bir fonksiyon — kendi rotasyon mantığınızı yazmanız için tam esneklik sağlar.
Her iki yaklaşım da HTTP, HTTPS ve SOCKS5 protokollerini destekler. Residential proxy'ler ile birleştiğinde, her istek farklı bir ISP'den geldiği için hedef site IP tabanlı engellemeleri zor uygular.
Colly Collector Modeli ve Callback Mimarisi
Colly'nin çekirdeği Collector struct'ıdır. Bir collector, HTTP isteklerinin yaşam döngüsünü yönetir ve üç ana callback zincirine sahiptir:
- OnRequest: İstek gönderilmeden önce çağrılır. Header'ları değiştirebilir, proxy'yi ayarlayabilirsiniz.
- OnHTML: Yanıt alındıktan sonra, goquery tabanlı DOM traversali ile CSS selector'lere göre elementleri yakalar.
- OnError: İstek başarısız olduğunda çağrılır — retry mantığı burada kurulur.
Colly varsayılan olarak asenkron modda çalışabilir. c.Async = true ayarı ile istekler goroutine'lerde paralel yürütülür. Bu, yüksek throughput gerektiren senaryolarda kritiktir, ancak paylaşılan state yönetimini zorlaştırır. Colly, bunun için sync.Mutex veya channel tabanlı desenler önerir.
goquery, jQuery benzeri bir API sunar ve Colly'nin OnHTML callback'inde *goquery.Selection olarak expose edilir. Bu sayede CSS selector'lerle DOM'da gezinmek, attribute'ları çekmek ve iç içe sorgular yazmak oldukça doğaldır.
Proxy Yüzeyi: RoundRobinProxySwitcher ve Custom Proxy Func
Colly'nin proxy paketi, hazır bir round-robin switcher sunar. Bu switcher, verilen proxy URL listesinde sırayla dolaşır ve her istekte bir sonrakini seçer.
RoundRobinProxySwitcher ile Basit Rotasyon
package main
import (
"fmt"
"log"
"github.com/gocolly/colly/v2"
"github.com/gocolly/colly/v2/proxy"
)
func main() {
c := colly.NewCollector()
// ProxyHat residential proxy URL'leri
proxies := []*url.URL{
url.Parse("http://user-country-DE-session-s1:pass@gate.proxyhat.com:8080"),
url.Parse("http://user-country-US-session-s2:pass@gate.proxyhat.com:8080"),
url.Parse("http://user-country-GB-session-s3:pass@gate.proxyhat.com:8080"),
}
switcher, err := proxy.RoundRobinProxySwitcher(proxies...)
if err != nil {
log.Fatal(err)
}
c.SetProxyFunc(switcher)
c.OnHTML("title", func(e *colly.HTMLElement) {
fmt.Println("Title:", e.Text)
})
c.Visit("https://example.com")
}
Custom Proxy Func ile Gelişmiş Rotasyon
Round-robin yeterli olmadığında — örneğin her istekte rastgele bir ülke seçmek veya başarısız proxy'leri geçici olarak devre dışı bırakmak istediğinizde — kendi func(*http.Request) (*url.URL, error) fonksiyonunuzu yazabilirsiniz.
func customProxySwitcher(proxies []*url.URL) colly.ProxyFunc {
var idx int
var mu sync.Mutex
return func(r *http.Request) (*url.URL, error) {
mu.Lock()
defer mu.Unlock()
p := proxies[idx%len(proxies)]
idx++
return p, nil
}
}
Bu desen, IP rotasyonunu tamamen kontrol altına almanızı sağlar. Örneğin, her isteğe benzersiz bir session-ID atayarak sticky session davranışı taklit edebilir veya belirli bir ülke için IP havuzu oluşturabilirsiniz.
Neden Residential IP'ler Gerekli?
Datacenter IP'leri, ASN (Autonomous System Number) bazlı tespit sistemlerinde kolayca flag'lenir. Cloudflare ve benzeri WAF sağlayıcıları, datacenter IP bloklarını bilinen bot trafik kaynakları olarak sınıflandırır. Residential IP'ler ise gerçek ISP'lerden (Deutsche Telekom, Comcast, Vodafone vb.) tahsis edildiği için normal kullanıcı trafiğinden ayırt edilmesi çok daha zordur.
ProxyHat'ın residential proxy servisinde, kullanıcı adı içinde ülke, şehir ve session parametreleri belirtebilirsiniz:
user-country-DE:pass— Almanya çıkış IP'siuser-country-DE-city-berlin:pass— Berlin şehir seviyesinde hedeflemeuser-session-abc123:pass— Aynı session ID ile aynı IP'yi koruyun (sticky session)
Bu parametreleri her istekte değiştirerek, coğrafi dağılımı kontrol edebilir ve aynı IP'den çok fazla istek gitmesini engelleyebilirsiniz.
Çalıştırılabilir Go Örneği: Residential Proxy ile Collector
Aşağıdaki örnek, ProxyHat residential proxy'leri ile çalışan, rate limit'li ve paralel istek yapan bir Colly collector'ıdır:
package main
import (
"fmt"
"log"
"math/rand"
"net/http"
"net/url"
"sync"
"time"
"github.com/gocolly/colly/v2"
"github.com/gocolly/colly/v2/proxy"
)
func main() {
c := colly.NewCollector(
colly.MaxDepth(2),
colly.UserAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64)"),
)
// ProxyHat residential proxy URL listesi
countries := []string{"DE", "US", "GB", "FR", "JP"}
var proxies []*url.URL
for _, cc := range countries {
u, _ := url.Parse(fmt.Sprintf(
"http://user-country-%s-session-%d:YOUR_PASSWORD@gate.proxyhat.com:8080",
cc, rand.Intn(10000),
))
proxies = append(proxies, u)
}
switcher, err := proxy.RoundRobinProxySwitcher(proxies...)
if err != nil {
log.Fatal(err)
}
c.SetProxyFunc(switcher)
// Rate limiting: paralellik ve gecikme
c.Limit(&colly.LimitRule{
DomainGlob: "*",
Parallelism: 10,
Delay: 2 * time.Second,
RandomDelay: 1 * time.Second,
})
var mu sync.Mutex
var results []string
c.OnHTML("h1", func(e *colly.HTMLElement) {
mu.Lock()
results = append(results, e.Text)
mu.Unlock()
})
c.OnError(func(r *colly.Response, err error) {
log.Printf("Hata: %s — status: %d", err, r.StatusCode)
})
targets := []string{
"https://example.com",
"https://example.org",
"https://example.net",
}
for _, t := range targets {
c.Visit(t)
}
c.Wait() // Asenkron modda tüm goroutine'lerin bitmesini bekle
for _, r := range results {
fmt.Println("Bulundu:", r)
}
}
Bu örnekte dikkat edilmesi gereken noktalar:
- Parallelism: 10 — Aynı anda en fazla 10 istek yürütülür.
- Delay + RandomDelay — Her istek arasında 2 saniye sabit + 0–1 saniye rastgele gecikme eklenir. Bu, trafiğin bot benzeri düzgünlüğünü kırar.
- Session ID — Her ülke için rastgele bir session ID üretilir, böylece aynı IP tekrar tekrar kullanılmaz.
Üretim Desenleri: Retry, Clone, Transport ve Dağıtık Scraping
Retry Mantığı: c.Clone() ile Yeniden Deneme
Colly'de retry yapmak için OnError callback'inde c.Clone() kullanarak collector'ın bir kopyasını oluşturabilir ve aynı URL'i tekrar ziyaret edebilirsiniz. Clone, proxy ayarlarını ve callback'leri kopyalar, ancak shared state'i kopyalamaz.
retryCount := make(map[string]int)
var retryMu sync.Mutex
maxRetries := 3
c.OnError(func(r *colly.Response, err error) {
retryMu.Lock()
n := retryCount[r.Request.URL.String()]
retryCount[r.Request.URL.String()] = n + 1
retryMu.Unlock()
if n < maxRetries {
time.Sleep(time.Duration(n+1) * 2 * time.Second) // Exponential backoff
r.Request.Retry()
}
})
Custom Transport ile TLS Fingerprint Yönetimi
Bazı anti-bot sistemleri TLS handshake fingerprint'ini kontrol eder. Colly, varsayılan http.Transport'ı özelleştirmenize olanak tanır:
c.WithTransport(&http.Transport{
TLSClientConfig: &tls.Config{
InsecureSkipVerify: false,
MinVersion: tls.VersionTLS12,
CipherSuites: []uint16{
tls.TLS_AES_128_GCM_SHA256,
tls.TLS_AES_256_GCM_SHA384,
tls.TLS_CHACHA20_POLY1305_SHA256,
},
},
MaxIdleConns: 100,
IdleConnTimeout: 90 * time.Second,
DisableCompression: false,
})
Dağıtık Scraping: Redis Storage Backend
Tek bir makine 500–1000 RPS'i geçtiğinde bottleneck olur. Colly, ziyaret edilen URL'leri paylaşmak için Redis ve SQLite storage backend'leri sunar. Birden fazla Colly instance'ı aynı Redis'e bağlanarak URL queue'yu paylaşabilir ve duplicate ziyaretleri önleyebilir.
storage := &storage.Redis{
Address: "redis://localhost:6379",
Prefix: "colly_scraper_",
}
c.SetStorage(storage)
Bu desen, Kubernetes pod'ları veya Docker container'ları arasında yatay ölçeklenme sağlar. Her pod, Redis'ten bir URL alır, işler ve sonucu ortak bir depoya yazar. ProxyHat'ın proxy lokasyonları ile birleştiğinde, her pod farklı bir bölgeden trafik gönderebilir.
Proxy Tipleri Karşılaştırması
| Özellik | Datacenter Proxy | Residential Proxy | Mobile Proxy |
|---|---|---|---|
| Tespit Zorluğu | Düşük (ASN tespiti kolay) | Yüksek (gerçek ISP) | Çok Yüksek |
| Hız / Latency | ~50ms | ~200–500ms | ~300–800ms |
| Fiyat (yaklaşık) | $0.50/GB | $2–5/GB | $5–15/GB |
| Anti-bot Bypass | Düşük başarı oranı | %90+ başarı | %95+ başarı |
| Uygun Senaryo | API scraping, basit siteler | SERP, e-ticaret, sosyal medya | Sosyal medya, sıkı anti-bot |
Colly Ne Zaman Kullanılmamalı?
Colly, HTTP istek-yanıt modeline dayanır. Eğer hedef site bir JavaScript SPA'sı ise (React, Vue, Angular) ve içerik client-side rendering ile geliyorsa, Colly'nin OnHTML callback'i boş bir DOM görecektir. Bu durumda chromedp veya Playwright gibi headless browser çözümleri daha uygundur.
Yine de Colly, headless browser fleet'leri ile birlikte kullanılabilir: Colly URL keşfi ve queue yönetimi için, chromedp ise rendering için. Bu hibrit yaklaşım, hem hız hem de rendering kapasitesi sağlar.
Etik ve Yasal Hususlar
- Yalnızca herkese açık verileri toplayın. Login arkasındaki verilere erişmek CFAA ihlali olabilir.
robots.txtdosyasını kontrol edin veDisallowkurallarına uyun.- GDPR kapsamında, AB vatandaşlarına ait kişisel verileri izinsiz toplamak ağır para cezalarına yol açabilir (en fazla €20 milyon veya global cironın %4'ü).
- Rate limitlere saygı gösterin — saniyede 100 istek göndermek bir siteyi DoS'a uğratabilir.
Key Takeaways
- Colly'de döner proxy,
SetProxyFuncile istek seviyesinde uygulanır;RoundRobinProxySwitcherveya customfunc(*http.Request) (*url.URL, error)kullanılabilir. - Residential proxy'ler, datacenter IP'lerine göre %90+ daha yüksek başarı oranı sunar ve anti-bot sistemlerinde tespit edilmesi çok daha zordur.
- ProxyHat kullanıcı adında
-country-DE-city-berlinve-session-abc123parametreleri ile her isteği coğrafi olarak yönlendirebilirsiniz. Limit()kuralları ile Parallelism ve RandomDelay ayarlamak, bot tespitini zorlaştırır.- Dağıtık scraping için Redis storage backend kullanın ve birden fazla pod/container arasında URL queue paylaşın.
- JS-heavy SPA'ler için Colly tek başına yeterli değildir; chromedp ile hibrit bir yaklaşım düşünün.
ProxyHat'ın residential proxy servisi ile Colly entegrasyonu hakkında daha fazla bilgi için fiyatlandırma sayfamızı inceleyin veya web scraping kullanım senaryolarımıza göz atın. SERP takibi için özel çözümlerimizi SERP tracking sayfamızda bulabilirsiniz. Teknik dokümantasyon için ProxyHat Docs adresini ziyaret edin.






