ما هو تدوير البروكسي في Colly ولماذا يهم مطوري Go؟
تدوير البروكسي في Colly هو نمط أساسي يسمح لمطوري Go بتوزيع الطلبات عبر عناوين IP متعددة لتجنب الحظر وتحسين معدلات النجاح. عند بناء كاشف ويب عالي الإنتاجية باستخدام إطار Colly، فإن الاعتماد على عنوان IP واحد يجعل تطبيقك عرضة للحظر بعد عدد صغير من الطلبات — غالبًا أقل من 100 طلب لكل دقيقة على المواقع المحمية بأنظمة مكافحة البوتات.
Colly هو إطار عمل لالتقاط بيانات الويب مكتوب بلغة Go، يعتمد على نموذج المُجمِّع (Collector) مع استدعاءات راجعة (callbacks) مثل OnRequest وOnHTML وOnError. يدعم التصفح غير المتزامن عبر goroutines، ويستخدم مكتبة goquery للتنقل في DOM باستخدام محددات CSS. يوفر Colly واجهة برمجية أنيقة لتدوير البروكسي عبر proxy.RoundRobinProxySwitcher وc.SetProxyFunc، مما يجعله مثاليًا لإدارة مئات الجلسات المتزامنة.
تنبيه قانوني وأخلاقي: هذا الدليل مخصص لجمع البيانات العامة فقط. تأكد من احترام ملف robots.txt وحدود المعدل (rate limits) وشروط الخدمة للمواقع المستهدفة. راجع RFC 9309 الخاص بـ robots.txt، وتوخَّ الحذر بشأن GDPR عند معالجة بيانات شخصية من دول الاتحاد الأوروبي.
نموذج المُجمِّع في Colly: فهم البنية الأساسية
قبل الغوص في تدوير البروكسي، من الضروري فهم البنية الأساسية لـ Colly. المُجمِّع (Collector) هو الكائن المركزي الذي يدير دورة حياة كل طلب HTTP. يمكنك تخصيص سلوكه عبر سلسلة من الاستدعاءات الراجعة:
OnRequest(func(*colly.Request))— يُستدعى قبل إرسال كل طلب، مثالي لضبط الترويسات (headers) أو تعديل البروكسي.OnHTML(goquerySelector, func(*colly.HTMLElement))— يُستدعى عند مطابقة محدد CSS، مع دعم goquery الكامل.OnError(func(*colly.Response, error))— يُستدعى عند فشل الطلب، مفيد لإعادة المحاولة.OnResponse(func(*colly.Response))— يُستدعى بعد استلام الاستجابة الكاملة.
يعمل Colly بشكل غير متزامن افتراضيًا، حيث يطلق goroutine لكل طلب. يمكنك التحكم في درجة التوازي عبر colly.Async(true) وc.Limit(&colly.LimitRule{...}). هذا النموذج غير المتزامن هو ما يجعل تدوير البروكسي ضروريًا — فبدونه، ستضرب جميع الطلبات المتزامنة الموقع المستهدف من نفس الـ IP.
واجهة البروكسي الأصلية في Colly
يوفر Colly حزمتين رئيسيتين لإدارة البروكسي: colly/proxy الذي يحتوي على RoundRobinProxySwitcher، والدالة c.SetProxyFunc التي تقبل دالة مخصصة بتوقيع func(*http.Request) (*url.URL, error).
استخدام RoundRobinProxySwitcher
التبديل الدائري (Round Robin) هو أبسط طريقة لتدوير البروكسي. يقوم بتوزيع الطلبات بالتساوي عبر قائمة بروكسي ثابتة:
package main
import (
"fmt"
"log"
"github.com/gocolly/colly/v2"
"github.com/gocolly/colly/v2/proxy"
)
func main() {
c := colly.NewCollector()
// قائمة بروكسي ProxyHat
proxies := []string{
"http://user-country-US:pass@gate.proxyhat.com:8080",
"http://user-country-DE:pass@gate.proxyhat.com:8080",
"http://user-country-GB:pass@gate.proxyhat.com:8080",
"http://user-country-FR:pass@gate.proxyhat.com:8080",
}
rp, err := proxy.RoundRobinProxySwitcher(proxies...)
if err != nil {
log.Fatal(err)
}
c.SetProxyFunc(rp)
c.OnHTML("title", func(e *colly.HTMLElement) {
fmt.Println("عنوان الصفحة:", e.Text)
})
c.Visit("https://example.com")
}
تبديل بروكسي مخصص مع SetProxyFunc
عندما تحتاج إلى تحكم أكبر — مثل تدوير الجلسات اللاصقة أو الاستهداف الجغرافي لكل طلب — يمكنك تمرير دالة مخصصة إلى SetProxyFunc:
package main
import (
"crypto/rand"
"fmt"
"math/big"
"net/http"
"net/url"
"github.com/gocolly/colly/v2"
)
func customProxySwitcher(req *http.Request) (*url.URL, error) {
countries := []string{"US", "DE", "GB", "FR", "JP"}
n, _ := rand.Int(rand.Reader, big.NewInt(int64(len(countries))))
country := countries[n.Int64()]
// توليد معرف جلسة عشوائي للجلسة اللاصقة
sessionID := fmt.Sprintf("sess-%d", n.Int64())
proxyURL := fmt.Sprintf(
"http://user-country-%s-session-%s:pass@gate.proxyhat.com:8080",
country, sessionID,
)
return url.Parse(proxyURL)
}
func main() {
c := colly.NewCollector()
c.SetProxyFunc(customProxySwitcher)
c.OnHTML("title", func(e *colly.HTMLElement) {
fmt.Println(e.Text)
})
c.Visit("https://example.com")
}
هذا النهج يمنحك تحكمًا كاملاً في اختيار البروكسي لكل طلب. يمكنك بناء منطق معقد: استخدام بروكسي سكني للمواقع المحمية، وبروكسي مركز بيانات للمواقع البسيطة، أو تثبيت الجلسة لنفس النطاق لتفادي مصادقة تسجيل الدخول المتكررة.
لماذا البروكسي السكني ضروري للأهداف الصعبة؟
البروكسي السكني يستخدم عناوين IP مخصصة لمزودي خدمة الإنترنت الحقيقيين، مما يجعل طلباتك تبدو وكأنها تأتي من مستخدمين عاديين. هذا أمر حاسم عند استهداف مواقع تستخدم أنظمة متقدمة مثل Cloudflare أو Datadome أو PerimeterX.
| نوع البروكسي | سرعة الاستجابة | معدل النجاح على المواقع المحمية | الاستخدام المثالي |
|---|---|---|---|
| سكني (Residential) | 200–800ms | 90–99% | SERP، التجارة الإلكترونية، وسائل التواصل |
| مركز بيانات (Datacenter) | 50–150ms | 30–60% | APIs عامة، مواقع غير محمية |
| محمول (Mobile) | 400–1500ms | 95–99% | تطبيقات الهاتف، وسائل التواصل الاجتماعي |
مع ProxyHat، يمكنك التحكم الدقيق في الاستهداف الجغرافي والجلسات عبر اسم المستخدم. على سبيل المثال، user-country-DE-city-berlin يوجه طلبك عبر IP سكني في برلين، بينما user-session-abc123 يضمن بقاء نفس الـ IP طوال الجلسة — وهو أمر حيوي عند التعامل مع مواقع تتطلب ملفات تعريف ارتباط متسقة.
مثال Go قابل للتشغيل: مُجمِّع كامل مع تدوير بروكسي سكني
المثال التالي يجمع كل القطع معًا: مُجمِّع Colly مع تبديل دائري للبروكسي السكني، قواعد حد المعدل، ومعالجة أخطاء مع إعادة المحاولة:
package main
import (
"fmt"
"log"
"sync/atomic"
"time"
"net/url"
"net/http"
"github.com/gocolly/colly/v2"
"github.com/gocolly/colly/v2/proxy"
)
var requestCounter uint64
func residentialProxySwitcher(req *http.Request) (*url.URL, error) {
countries := []string{"US", "DE", "GB", "FR", "NL", "CA", "JP"}
idx := atomic.AddUint64(&requestCounter, 1)
country := countries[idx % uint64(len(countries))]
sessionID := fmt.Sprintf("colly-%d", idx)
proxyStr := fmt.Sprintf(
"http://user-country-%s-session-%s:YOUR_PASSWORD@gate.proxyhat.com:8080",
country, sessionID,
)
return url.Parse(proxyStr)
}
func main() {
c := colly.NewCollector(
colly.Async(true),
)
// ضبط قواعد الحد: 5 طلبات متوازية كحد أقصى، تأخير عشوائي 1–3 ثوانٍ
err := c.Limit(&colly.LimitRule{
DomainGlob: "*",
Parallelism: 5,
RandomDelay: 2 * time.Second,
})
if err != nil {
log.Fatal(err)
}
// تعيين دالة البروكسي المخصصة
c.SetProxyFunc(residentialProxySwitcher)
// تعيين ترويسات واقعية
c.OnRequest(func(r *colly.Request) {
r.Headers.Set("Accept", "text/html,application/xhtml+xml")
r.Headers.Set("Accept-Language", "en-US,en;q=0.9")
r.Headers.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64)")
})
c.OnHTML("h1", func(e *colly.HTMLElement) {
fmt.Printf("[%s] H1: %s\n", e.Request.URL, e.Text)
})
c.OnHTML("a[href]", func(e *colly.HTMLElement) {
link := e.Attr("href")
e.Request.Visit(link)
})
c.OnError(func(r *colly.Response, err error) {
log.Printf("خطأ في %s: %v (الحالة: %d)", r.Request.URL, err, r.StatusCode)
// استنساخ المُجمِّع لإعادة المحاولة ببروكسي مختلف
if r.StatusCode == 403 || r.StatusCode == 429 {
clone := r.Request.C.Clone()
clone.SetProxyFunc(residentialProxySwitcher)
clone.Visit(r.Request.URL.String())
}
})
urls := []string{
"https://example.com",
"https://example.org",
"https://example.net",
}
for _, u := range urls {
c.Visit(u)
}
c.Wait()
}
هذا المثال يوضح عدة مفاهيم مهمة: استخدام atomic.AddUint64 لعدّ آمن للتزامن، تدوير الدول مع كل طلب، جلسات لاصقة فريدة لكل طلب، وc.Clone() لإعادة المحاولة ببروكسي جديد عند استلام رمز 403 أو 429.
دعم SOCKS5 مع ProxyHat
عندما تحتاج إلى نفق أكثر أمانًا أو تجاوز قيود جدار الحماية، يمكنك استخدام بروكسي SOCKS5 عبر المنفذ 1080:
func socks5ProxySwitcher(req *http.Request) (*url.URL, error) {
proxyStr := "socks5://user-country-DE-city-berlin:pass@gate.proxyhat.com:1080"
return url.Parse(proxyStr)
}
func main() {
c := colly.NewCollector()
c.SetProxyFunc(socks5ProxySwitcher)
c.Visit("https://example.com")
}
لاحظ أن Colly يستخدم net/http.Transport داخليًا، والذي يدعم SOCKS5 عبر golang.org/x/net/proxy. تأكد من استيراد الحزمة المناسبة إذا كنت تبني Transport مخصصًا.
أنماط الإنتاج: التوسع والموثوقية
إعادة المحاولة مع c.Clone()
في الإنتاج، ستفشل بعض الطلبات حتمًا. بدلاً من إعادة المحاولة على نفس البروكسي المحظور، استخدم c.Clone() لإنشاء مُجمِّع جديد يحمل نفس التكوين ولكن يبدأ بدورة بروكسي جديدة. هذا النمط يحافظ على فصل الاهتمامات (separation of concerns) دون تكرار التكوين:
c.OnError(func(r *colly.Response, err error) {
if r.StatusCode >= 400 {
retryClone := c.Clone()
retryClone.SetProxyFunc(residentialProxySwitcher)
time.Sleep(3 * time.Second)
retryClone.Visit(r.Request.URL.String())
}
})
تأخير عشوائي وتحديد التوازي
الطلبات المتتابعة السريعة من نفس الـ IP هي أكثر أسباب الحظر شيوعًا. استخدم RandomDelay وParallelism للتحكم في الإيقاع. القيمة المثالية تعتمد على الموقع المستهدف: المواقع الصغيرة قد تتحمل 5 طلبات/ثانية، بينما محركات البحث الكبرى قد تتطلب تأخيرًا يصل إلى 5 ثوانٍ بين الطلبات.
تخصيص Transport لـ TLS
بعض المواقع تتطلب بصمة TLS معينة لتجاوز فحوصات البوت. يمكنك تخصيص http.Transport الأساسي في Colly:
c.WithTransport(&http.Transport{
TLSClientConfig: &tls.Config{
InsecureSkipVerify: false,
MinVersion: tls.VersionTLS12,
},
MaxIdleConns: 100,
MaxIdleConnsPerHost: 10,
IdleConnTimeout: 30 * time.Second,
})
التوزيع عبر Redis Storage
عند التوسع إلى عقد متعددة، استخدم storage.RedisStorage لمشاركة حالة الزيارات بين مثيلات Colly المختلفة. هذا يمنع زيارة نفس الرابط مرتين ويوزع الحمل:
import "github.com/gocolly/colly/v2/storage"
storage := &storage.RedisStorage{
Address: "redis://localhost:6379",
Prefix: "colly_scraper_",
}
c.SetStorage(storage)
يمكنك تشغيل عدة حاويات Docker لكل منها مُجمِّع Colly خاص، مع مشاركة قائمة انتظار Redis. هذا النمط يتيح التوسع الأفقي إلى 100+ جلسة متزامنة. راجع وثائق ProxyHat لتفاصيل حدود التزامن لكل خطة.
متى لا تستخدم Colly
Colly ممتاز للصفحات المقدمة من الخادم (server-rendered HTML)، لكنه لا ينفذ JavaScript. إذا كان الموقع المستهدف تطبيق صفحة واحدة (SPA) يعتمد على React أو Vue لعرض المحتوى، فلن تجد Colly أي بيانات. في هذه الحالة، استخدم متصفحًا مقادًا عن بُعد مثل chromedp أو Rod، مع توجيه البروكسي عبر --proxy-server في Chromium.
يمكنك أيضًا دمج Colly مع متصفح مقاد: استخدم chromedp لعرض الصفحة، ثم مرر HTML الناتج إلى Colly عبر c.OnResponse. هذا النهج الهجين يجمع بين قوة عرض JavaScript وكفاءة Colly في تحليل DOM.
الاعتبارات الأخلاقية والقانونية
تدوير البروكسي أداة قوية، لكنها يجب أن تُستخدم بمسؤولية:
- احترام robots.txt: تحقق دائمًا من
/robots.txtقبل الكشط. راجع RFC 9309 للمواصفات الكاملة. - البيانات العامة فقط: لا تتجاوز مصادقة أو جدران دفع. قانون CFAA في الولايات المتحدة يجرم الوصول غير المصرح به لأنظمة الكمبيوتر.
- GDPR: عند معالجة بيانات شخصية لمواطني الاتحاد الأوروبي، تأكد من وجود أساس قانوني. راجع gdpr.eu للإرشادات.
- حدود المعدل: حتى مع البروكسي السكني، حافظ على معدل معقول. الكشط العدواني يضر بالبنية التحتية للموقع المستهدف.
إعداد ProxyHat مع Colly
للبدء مع ProxyHat، ستحتاج إلى حساب نشط. يمكنك مراجعة خطط الأسعار والمواقع المتاحة. للاستخدام في حالات الكشط العام، راجع حالة استخدام كشط الويب وتتبع نتائج البحث.
جميع أمثلة هذا الدليل تستخدم gate.proxyhat.com:8080 للبروكسي HTTP وgate.proxyhat.com:1080 لـ SOCKS5. استبدل USERNAME وPASSWORD ببيانات اعتماد حسابك الفعلية.
النقاط الرئيسية
- تدوير البروكسي في Colly ضروري لأي كاشف ويب عالي الإنتاجية — استخدم
proxy.RoundRobinProxySwitcherللتبديل البسيط وSetProxyFuncللتحكم الكامل.- البروكسي السكني يحقق معدلات نجاح تصل إلى 99% على المواقع المحمية، مقارنة بـ 30–60% لبروكسي مركز البيانات.
- استخدم أعلام
-country-DE-city-berlinو-session-abc123في اسم المستخدم للاستهداف الجغرافي والجلسات اللاصقة.c.Clone()هو النمط الأنسب لإعادة المحاولة ببروكسي جديد عند استلام 403/429.- اضبط
ParallelismوRandomDelayلتجنب الحظر حتى مع البروكسي السكني.- لا يستطيع Colly تنفيذ JavaScript — استخدم chromedp للصفحات الديناميكية.
الأسئلة الشائعة
ما هو تدوير البروكسي في Colly؟
تدوير البروكسي في Colly هو عملية توزيع طلبات HTTP عبر عناوين IP متعددة باستخدام واجهة SetProxyFunc أو proxy.RoundRobinProxySwitcher. يسمح ذلك للمُجمِّع (Collector) بإرسال كل طلب من عنوان IP مختلف، مما يقلل من خطر الحظر ويحسن معدلات النجاح عند كشط المواقع المحمية بأنظمة مكافحة البوتات.
لماذا يهم تدوير البروكسي في Colly لمستخدمي البروكسي؟
بدون تدوير البروكسي، جميع الطلبات من مُجمِّع Colly ستأتي من نفس الـ IP، مما يؤدي إلى الحظر بعد عدد محدود من الطلبات — غالبًا أقل من 100 طلب لكل دقيقة. التدوير يوزع الحمل عبر IPs متعددة، مما يقلل الضغط على كل عنوان ويزيد من إجمالي الإنتاجية. مع البروكسي السكني من ProxyHat، يمكنك تحقيق معدلات نجاح تصل إلى 99%.
أي نوع بروكسي يعمل بشكل أفضل مع تدوير البروكسي في Colly؟
البروكسي السكني (Residential) هو الخيار الأفضل للمواقع المحمية، لأنه يستخدم عناوين IP من مزودي خدمة الإنترنت الحقيقيين، مما يجعل الطلبات تبدو طبيعية. البروكسي المحمول (Mobile) مناسب أيضًا ولكنه أبطأ. البروكسي مركز البيانات أسرع لكنه يُكتشف بسهولة من قبل أنظمة مثل Cloudflare. استخدم SOCKS5 عبر المنفذ 1080 عند الحاجة لنفق أكثر أمانًا.
كيف تتجنب الحظر عند تنفيذ تدوير البروكسي في Colly؟
لتجنب الحظر: (1) استخدم بروكسي سكني مع تدوير لكل طلب، (2) اضبط Parallelism على 5 أو أقل وRandomDelay بين 1–3 ثوانٍ، (3) استخدم c.Clone() لإعادة المحاولة ببروكسي مختلف عند استلام 403 أو 429، (4) اضبط ترويسات واقعية في OnRequest، (5) احترم robots.txt وحدود المعدل للموقع المستهدف.
هل يمكنني استخدام جلسات لاصقة مع Colly وProxyHat؟
نعم. أضف -session-abc123 إلى اسم المستخدم في عنوان البروكسي للحفاظ على نفس الـ IP طوال الجلسة. هذا مفيد للمواقع التي تتطلب ملفات تعريف ارتباط متسقة أو مصادقة متعددة الخطوات. غيّر معرف الجلسة عند الحاجة إلى IP جديد، واحتفظ بنفس المعرف للحفاظ على الاتصال.






