مقدمه
این راهنما به شما نشان میدهد چگونه پروکسیها را با کتابخانه Go Colly در پروژههای وب اسکریپینگ استفاده و مدیریت کنید. اگرچه مثالها با زبان Go نوشته شدهاند، مفاهیم برای توسعهدهندگان دیگر زبانها (مثل Python) نیز قابلانتقال است. در پایان این مقاله خواهید دانست که چگونه پروکسی ساده تنظیم کنید، با پروکسیهای دارای احراز هویت کار کنید، لیست پروکسیها را بچرخانید، از دروازههای پروکسی و APIهای پروکسی استفاده کنید و نکات عملی برای پایدارسازی و امنسازی اسکریپر را پیادهسازی کنید.
استفاده از پروکسی IP با Go Colly
برای افزودن یک پروکسی ساده کافی است روی کالکتر SetProxy را فراخوانی کنید. مثال کوتاه زیر یک درخواست میفرستد و پاسخ را چاپ میکند.
package main
import (
"bytes"
"log"
"github.com/gocolly/colly"
)
func main() {
// Instantiate default collector
c := colly.NewCollector(colly.AllowURLRevisit())
// Set Proxy
c.SetProxy("http://proxy.example.com:8080")
// Print the Response
c.OnResponse(func(r *colly.Response) {
log.Printf("%s\n", bytes.Replace(r.Body, []byte("\\n"), nil, -1))
})
// On Error Print Error
c.OnError(func(_ *colly.Response, err error) {
log.Println("Something went wrong:", err)
})
// Request Page
c.Visit("https://httpbin.org/ip")
}
توضیح کد:
- c := colly.NewCollector(...): کالکتر را میسازد؛ میتوان تنظیمات concurrency یا user-agent را اینجا اضافه کرد.
- c.SetProxy: یک پروکسی واحد را برای تمام درخواستها تنظیم میکند.
- c.OnResponse: هندلری که هنگام دریافت پاسخ فراخوانی میشود؛ ورودی آن *colly.Response است و خروجی تابع معمولاً لاگ یا پردازش دادههاست.
- c.OnError: برای لاگگیری خطاها؛ از اینجا میتوان منطق retry را اجرا کرد.
- c.Visit: آدرس مورد نظر را درخواست میکند.
نکته: این روش برای درخواستهای GET/POST/PUT/... که Colly پشتیبانی میکند مناسب است. اما اگر نیاز به چرخش پروکسی یا مدیریت وضعیت پروکسیها دارید، روشهای بعدی را ببینید.
احراز هویت پروکسی
برای پروکسیهایی که نیاز به username و password دارند، کافیست آنها را در رشتهٔ پروکسی بگنجانید:
package main
import (
"bytes"
"log"
"github.com/gocolly/colly"
)
func main() {
c := colly.NewCollector(colly.AllowURLRevisit())
// Proxy with basic auth credentials
c.SetProxy("http://USERNAME:PASSWORD@proxy.example.com:8080")
c.OnResponse(func(r *colly.Response) {
log.Printf("%s\n", bytes.Replace(r.Body, []byte("\\n"), nil, -1))
})
c.OnError(func(_ *colly.Response, err error) {
log.Println("Something went wrong:", err)
})
c.Visit("https://httpbin.org/ip")
}
نکات امنیتی و عملی:
- هرگز کلیدها یا پسوردها را در کد منبع عمومی قرار ندهید؛ از متغیر محیطی یا سرویس مخفیسازی استفاده کنید.
- برخی پروکسیها از روشهای احراز هویت پیچیدهتر (مانند توکنها یا headerهای سفارشی) استفاده میکنند که باید با افزودن header مناسب به درخواستها مدیریت شوند.
فرمتهای متداول پروکسی و مقایسه
سه فرمت متداول پروکسی که امروزه ارائه میشوند عبارتاند از:
- لیست IPهای پروکسی: شما یک لیست خام از آدرسها و پورتها میگیرید و باید خودتان چرخش و سلامت آنها را مدیریت کنید.
- دروازه (Proxy Gateway): یک نقطه انتهایی واحد که خودش پروکسیها را در پشت صحنه مدیریت میکند؛ سادهتر برای ادغام اما هزینهبرتر یا همراه با محدودیت است.
- API پروکسی: شما URL را به API ارسال میکنید و API پاسخ HTML را برمیگرداند؛ پروکسی و headerها معمولاً توسط فراهمکننده مدیریت میشوند.
ادغام #1: چرخش از طریق لیست پروکسی
اگر تامینکنندهتان یک لیست پروکسی میدهد، سادهترین روش استفاده از proxy.RoundRobinProxySwitcher در بستهٔ Colly است. ابتدا بستهٔ پروکسی را نصب کنید:
go get github.com/gocolly/colly/proxy
نمونهٔ کد چرخش ساده:
package main
import (
"bytes"
"log"
"github.com/gocolly/colly"
"github.com/gocolly/colly/proxy"
)
func main() {
c := colly.NewCollector(colly.AllowURLRevisit())
proxyList := []string{
"http://Username:Password@85.237.57.198:20000",
"http://Username:Password@85.237.57.198:21000",
"http://Username:Password@85.237.57.198:22000",
"http://Username:Password@85.237.57.198:23000",
}
rp, err := proxy.RoundRobinProxySwitcher(proxyList...)
if err != nil {
log.Fatal(err)
}
// Use proxy switcher function
c.SetProxyFunc(rp)
c.OnResponse(func(r *colly.Response) {
log.Printf("%s\n", bytes.Replace(r.Body, []byte("\\n"), nil, -1))
})
c.OnError(func(_ *colly.Response, err error) {
log.Println("Something went wrong:", err)
})
for i := 0; i < 5; i++ {
c.Visit("https://httpbin.org/ip")
}
}
توضیح و نکات اجرایی:
- ورودی: proxyList آرایهای از رشتههایی است که شامل آدرس، پورت و اختیاری اطلاعات احراز هویت است.
- خروجی: هر درخواست توسط یکی از پروکسیهای لیست فرستاده میشود (بهصورت round-robin).
- نکتهٔ مقیاسپذیری: این روش پایهای است؛ در مقیاس بالا باید مکانیزمی برای سنجش latency، نرخ خطا و حذف پروکسیهای مشکلدار اضافه کنید.
- مدیریت خطا: در c.OnError میتوانید منطق retry با backoff و حذف پروکسیهای ناکارآمد را پیادهسازی کنید.
ادغام #2: استفاده از دروازهٔ پروکسی
در این مدل، تامینکننده یک endpoint واحد ارائه میکند که خودش ترافیک را به زیرمجموعهٔ پروکسیها هدایت میکند. کار شما صرفاً تنظیم یک پروکسی است. مثال زیر نشان میدهد چگونه از یک دروازهٔ مسکونی مانند BrightData استفاده کنید:
package main
import (
"bytes"
"log"
"github.com/gocolly/colly"
)
func main() {
c := colly.NewCollector(colly.AllowURLRevisit())
// Single gateway proxy
c.SetProxy("http://zproxy.lum-superproxy.io:22225")
c.OnResponse(func(r *colly.Response) {
log.Printf("%s\n", bytes.Replace(r.Body, []byte("\\n"), nil, -1))
})
c.OnError(func(_ *colly.Response, err error) {
log.Println("Something went wrong:", err)
})
c.Visit("https://httpbin.org/ip")
}
مزایا و معایب:
- مزایا: ساده، مدیریت داخلی چرخش، احتمالاً بهینهشده برای residential/mobile.
- معایب: معمولاً کمتر کنترلی روی انتخاب آیپیها دارید و ممکن است هزینه یا محدودیتهایی داشته باشد.
ادغام #3: استفاده از API پروکسی
برخی تامینکنندگان APIهای هوشمند ارائه میدهند که شما آدرس هدف را به آنها میفرستید و آنها نتیجهٔ HTML را بازمیگردانند. نمونه زیر با ScrapeOps نشان میدهد چگونه پارامترها را URL-encode کنید و درخواست را ارسال نمایید.
package main
import (
"bytes"
"log"
"github.com/gocolly/colly"
"net/url"
)
func main() {
c := colly.NewCollector(colly.AllowURLRevisit())
c.OnResponse(func(r *colly.Response) {
log.Printf("%s\n", bytes.Replace(r.Body, []byte("\\n"), nil, -1))
})
c.OnError(func(_ *colly.Response, err error) {
log.Println("Something went wrong:", err)
})
// Build proxy API URL
u, err := url.Parse("https://proxy.scrapeops.io/v1/")
if err != nil {
log.Fatal(err)
}
q := u.Query()
q.Set("api_key", "YOUR_API_KEY") // از متغیر محیطی استفاده کنید
q.Set("url", "https://httpbin.org/ip")
u.RawQuery = q.Encode()
// Visit the full API URL
c.Visit(u.String())
}
نکات مهم:
- همیشه پارامتر url را URL-encode کنید تا پارامترهای هدف با پارامترهای API تداخل نداشته باشند.
- کلیدهای API را در متغیرهای محیطی نگه دارید و در لاگها یا مخزن کد منتشر نکنید.
- برخی APIها میتوانند پاسخهای cache شده یا headerهای تغییر یافته برگردانند؛ قبل از استفاده در تولید، مستندات آن API را مطالعه کنید.
نکات عملی، عملکرد و پایداری
- کنترل نرخ: از محدودکنندههای نرخ (rate limiter) برای جلوگیری از ارسال درخواستهای سریع پشتسرهم استفاده کنید.
- همزمانی: Colly از همزمانی پشتیبانی میکند؛ اما با افزایش concurrency نیاز به مدیریت pool پروکسی و هماهنگی بیشتر دارید.
- مانیتورینگ و لاگینگ: métrics برای میزان خطا، latency و نرخ موفقیت هر پروکسی جمعآوری کنید و بر اساس آن تصمیم به حذف یا تضعیف یک پروکسی بگیرید.
- استراتژی retry: از backoff تصاعدی و حداکثر تعداد تلاش استفاده کنید تا بار اضافی به سایت هدف وارد نشود.
- امنیت: از HTTPS برای ارتباط با دروازهها و APIهای پروکسی استفاده کنید و از افشای API key جلوگیری کنید.
- هدرها و یوزر-اجنتها: چرخش User-Agent و مدیریت کوکیها میتواند احتمال بلاک شدن را کاهش دهد.
- احترام به قوانین: همواره سیاست سایت هدف و قوانین محلی را بررسی کنید؛ وب اسکریپینگ مسئولانه انجام دهید.
جمعبندی
در این مقاله سه روش اصلی ادغام پروکسی با Go Colly را دیدیم: تنظیم پروکسی ساده، چرخش با لیست پروکسی، استفاده از دروازه و استفاده از API پروکسی. هر روش مزایا و محدودیتهای خود را دارد؛ انتخاب مناسب بستگی به مقیاس، بودجه و نیاز به کنترل روی آیپیها دارد. مهمترین نکات عملی عبارتاند از مدیریت کلیدها بهصورت امن، پیادهسازی مانیتورینگ پروکسیها، کنترل نرخ و استراتژیهای retry. با پیادهسازی این راهکارها میتوانید یک اسکریپر پایدارتر و کمتر در معرض بلاک شدن بسازید.





