خانه/مقالات/راهنمای کامل وب اسکریپینگ با Golang Colly و User-Agent‌های تصادفی
پروکسی و چرخش IP
ضد بلاک (Anti-bot)
برگشت به صفحه مقاله ها
راهنمای کامل وب اسکریپینگ با Golang Colly و User-Agent‌های تصادفی

راهنمای کامل وب اسکریپینگ با Golang Colly و User-Agent‌های تصادفی

این مقاله به صورت گام‌به‌گام نحوهٔ استفاده و چرخش User-Agentهای جعلی در اسکریپرهای Golang با Colly را توضیح می‌دهد؛ از روش سادهٔ تنظیم هدر تا دریافت لیست‌های به‌روز از API و استفاده از مجموعهٔ کامل هدرهای مرورگر برای کاهش شناسایی. همچنین بهترین‌روش‌ها، نکات امنیتی، مدیریت خطا و مثال‌های کد آماده ارائه شده است تا اسکریپرهای قابل‌اطمینان‌تری بسازید.
امیر حسین حسینیان
امیر حسین حسینیان
1404-09-12

مقدمه

در این مقاله همگام با مثال‌های عملی یاد می‌گیریم چگونه در اسکریپرهای نوشته‌شده با Golang و کتابخانه Colly از User-Agent‌های جعلی (fake user-agents) استفاده و آنها را چرخانده (rotate) و در مقیاس بزرگ مدیریت کنیم. این راهنما برای توسعه‌دهنده‌های پایتون/گو در سطح متوسط نوشته شده که می‌خواهند با جزئیات فنی کار با هدرها، مدیریت خطا، بهترین روش‌ها و نمونه‌کدهای قابل اجرا آشنا شوند. در پایان شما قادر خواهید بود: تنظیم User-Agent ثابت، چرخش تصادفی، استفاده از افزونهٔ RandomUserAgent، دریافت لیست‌های به‌روز از API و جایگذاری مجموعه کامل headerهای مرورگر برای کاهش تشخیص شدن توسط سایت‌ها را پیاده‌سازی کنید.

What Are Fake User-Agents?

User-Agent رشته‌ای است که مرورگر یا کلاینت هنگام ارسال درخواست HTTP به سرور ارسال می‌کند تا مشخصات برنامه، سیستم عامل و مرورگر را اعلام کند. هنگام وب اسکریپینگ اگر User-Agent پیش‌فرض کتابخانه (مثل User-Agent پیش‌فرض Colly) را استفاده کنید، سایت به‌راحتی متوجه می‌شود که درخواست‌ها توسط یک اسکریپر ارسال می‌شوند و ممکن است آن را مسدود کند.

مثال یک User-Agent واقعی (نمونه):

'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.82 Safari/537.36'

بنابراین استفاده از User-Agent‌های جعلی و به‌خصوص مجموعه‌ای از هدرهای مرورگر واقعی می‌تواند احتمال بلاک شدن را کاهش دهد.

تنظیم یک User-Agent ثابت در Go Colly

ایجاد یک هدر ثابت خیلی ساده است: کافی است در هندلر c.OnRequest مقدار هدر User-Agent را تنظیم کنید. نمونهٔ ساده:

package main

import (
	"bytes"
	"log"
	"github.com/gocolly/colly"
)

func main() {
	// Instantiate default collector
	c := colly.NewCollector(colly.AllowURLRevisit())

	// Set Fake User Agent
	c.OnRequest(func(r *colly.Request) {
		r.Headers.Set("User-Agent", "Mozilla/5.0 (iPad; CPU OS 12_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148")
	})

	// Print the Response body (single-line)
	c.OnResponse(func(r *colly.Response) {
		log.Printf("%s\n", bytes.Replace(r.Body, []byte("\n"), nil, -1))
	})

	for i := 0; i < 5; i++ {
		c.Visit("http://httpbin.org/headers")
	}
}

توضیح ورودی/خروجی و نقش توابع:

  • ورودی: هیچ ورودی خارجی نیاز ندارد مگر URLهایی که در c.Visit قرار می‌دهید.
  • خروجی: لاگ پاسخ‌های سرور چاپ می‌شود.
  • c.OnRequest: هر بار که درخواست جدید ساخته می‌شود فراخوانی شده و اینجا هدرها را تنظیم می‌کنیم.
  • c.OnResponse: پاسخ را دریافت و پردازش می‌کند؛ در این مثال فقط آن را لاگ کرده‌ایم.

نکته: این روش برای تست یا اسکریپ‌های کوچک مناسب است اما در مقیاس بالا استفاده از یک User-Agent ثابت باعث شناسایی سریع می‌شود.

چرخش User-Agentهای تصادفی

برای سخت‌تر کردن شناسایی، بهتر است برای هر درخواست یک User-Agent تصادفی انتخاب کنید. الگوریتم کلی: یک لیست از User-Agentها داشته باشید و در c.OnRequest یک مقدار تصادفی از آن انتخاب کنید.

package main

import (
	"bytes"
	"log"
	"math/rand"
	"time"
	"github.com/gocolly/colly"
)

func RandomString(list []string) string {
	return list[rand.Intn(len(list))]
}

func main() {
	rand.Seed(time.Now().UnixNano()) // مهم: هر بار برنامه اجرا شود seed متفاوت باشد

	c := colly.NewCollector(colly.AllowURLRevisit())

	userAgentList := []string{
		"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.82 Safari/537.36",
		"Mozilla/5.0 (iPhone; CPU iPhone OS 14_4_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0.3 Mobile/15E148 Safari/604.1",
		"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.53 Safari/537.36",
	}

	c.OnRequest(func(r *colly.Request) {
		r.Headers.Set("User-Agent", RandomString(userAgentList))
	})

	c.OnResponse(func(r *colly.Response) {
		log.Printf("%s\n", bytes.Replace(r.Body, []byte("\n"), nil, -1))
	})

	for i := 0; i < 5; i++ {
		c.Visit("http://httpbin.org/headers")
	}
}

نکات عملی و بهترین روش‌ها:

  • حتماً یک seed مناسب برای math/rand تنظیم کنید تا هر اجرا الگو تکراری نداشته باشد.
  • برای استفادهٔ همزمان (concurrency) اگر از منابع تصادفی مشترک استفاده می‌کنید، به thread-safety توجه کنید؛ می‌توانید از یک rand.New(rand.NewSource(...)) محلی یا sync.Mutex برای محافظت استفاده کنید.
  • در صورت نیاز به randomness قوی‌تر (ولی کندتر) از crypto/rand استفاده کنید؛ معمولاً برای انتخاب UA کافی نیست.

استفاده از افزونه RandomUserAgent

Colly یک افزونهٔ ساده به نام extensions.RandomUserAgent دارد که لیستی از User-Agentهای داخلی را تولید و برای هر درخواست انتخاب می‌کند. استفادهٔ آن بسیار ساده است:

package main

import (
	"bytes"
	"log"
	"github.com/gocolly/colly"
	"github.com/gocolly/colly/extensions"
)

func main() {
	c := colly.NewCollector(colly.AllowURLRevisit())

	// Add Random User Agents
	extensions.RandomUserAgent(c)

	c.OnResponse(func(r *colly.Response) {
		log.Printf("%s\n", bytes.Replace(r.Body, []byte("\n"), nil, -1))
	})

	for i := 0; i < 5; i++ {
		c.Visit("http://httpbin.org/headers")
	}
}

محدودیت: مجموعهٔ داخلی ممکن است کوچک یا قدیمی باشد؛ برای اسکریپ‌های جدی‌تر بهتر است از لیست‌های به‌روزتر استفاده شود.

مدیریت هزاران User-Agent با API

راه قدرتمندتر این است که لیست به‌روز User-Agentها را هنگام شروع اسکریپر از یک API معتبر دریافت کنید، آن را کش (cache) کرده و برای هر درخواست یک مقدار تصادفی انتخاب کنید. نکات مهم:

  • کلید API را در متغیرهای محیطی قرار دهید و هرگز در کد سخت‌کد نکنید.
  • از یک http.Client با timeout مناسب استفاده کنید تا اپلیکیشن در وضعیت‌های شبکه‌ای بلوکه نشود.
  • در صورت خطا هنگام دریافت لیست، حافظهٔ محلی (fallback) یا تعداد محدودی UA را استفاده کنید و لاگ کنید.

نمونهٔ خلاصه‌شدهٔ تابع دریافت لیست (الگوی کلی):

// الگو: GetUserAgentList() -> []string
//  - از API لیست را می‌خواند
//  - در صورت موفقیت json را دیکد کرده و []string برمی‌گرداند
//  - در صورت خطا یک slice خالی بازمی‌گرداند

نکات عملی دربارهٔ کش و نرخ‌محدودیت‌ها (rate limits):

  • لیست را فقط یک‌بار در ابتدای اجرای اسکریپر دانلود کنید و در حافظه نگه دارید؛ می‌توانید هر 24–6 ساعت آن را تازه کنید.
  • بررسی کنید API نرخ محدودیت دارد و اگر دارد از استراتژی backoff برای retry استفاده کنید.
  • برای محیط توزیع‌شده، می‌توانید لیست را در یک storage مرکزی (مثلاً cache حافظه توزیع‌شده) ذخیره کنید تا همه نمونه‌ها از همان مجموعه استفاده کنند.

Fake Browser Headers — فراتر از User-Agent

سایت‌های مدرن علاوه بر User-Agent به سایر هدرهای مرورگر (مثل Accept, Accept-Language, sec-ch-ua و غیره) نگاه می‌کنند. ارسال مجموعه‌ای از هدرهای هم‌خوان با یک مرورگر واقعی شانس شناسایی شدن را کاهش می‌دهد.

نمونه‌ای از هدرهای ارسالی توسط Chrome روی macOS (مثال):

sec-ch-ua: " Not A;Brand";v="99", "Chromium";v="99", "Google Chrome";v="99"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "macOS"
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.83 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Sec-Fetch-Site: none
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Accept-Encoding: gzip, deflate, br
Accept-Language: en-GB,en-US;q=0.9,en;q=0.8

به جای ساختن دستی این مجموعه‌ها، می‌توانید از یک API که هدرهای بهینه‌شده بازمی‌گرداند (مثل نمونه‌هایی که در این راهنما به آنها اشاره شده) استفاده کنید و برای هر درخواست یک مجموعهٔ کامل هدر انتخاب کنید:

// در OnRequest: پس از انتخاب یک map[string]string از لیست هدرها
for k, v := range randomHeaderMap {
	r.Headers.Set(k, v)
}

عملکرد، خطاها و امنیت

موارد مهمی که در تولید یک اسکریپر مقاوم و پایدار باید در نظر بگیرید:

  • Rate limiting: با time.Sleep یا یک کنترل‌کننده نرخ (rate limiter) بین درخواست‌ها، از فشار بیش‌ازحد روی سایت جلوگیری کنید.
  • Retries و backoff: برای خطاهای موقت شبکه از استراتژی exponential backoff استفاده کنید و تعداد retry را محدود نگه دارید.
  • Proxies: اگر نیاز به IP rotation دارید از پراکسی‌های قابل اطمینان استفاده کنید و ترکیب پراکسی + header rotation را پیاده کنید.
  • ذخیرهٔ امن API keys: از متغیر محیطی یا vault استفاده کنید؛ هرگز کلیدها را در مخزن کد ذخیره نکنید.
  • قوانین و اخلاق: قبل از اسکریپ کردن محتوای سایت، سیاست‌های سایت و قوانین را بررسی کنید و به robots.txt و شرایط استفاده احترام بگذارید.

جمع‌بندی

تنظیم و چرخش User-Agentها در Colly ساده است اما برای قابل‌اطمینان و مقاوم کردن اسکریپرها لازم است: الف) برای هر درخواست User-Agent متفاوت انتخاب کنید، ب) در صورت امکان مجموعه کامل هدرهای مرورگر را نیز ارسال کنید، ج) از لیست‌های به‌روز (مثلاً از یک API) استفاده کرده و آن‌ها را کش کنید، و د) به مسائل عملکرد، retry، پراکسی و امنیت کلیدها توجه کنید. با رعایت این نکات می‌توانید احتمال بلاک شدن را به طور قابل توجهی کاهش دهید و اسکریپرهای پایدارتری داشته باشید.

مقاله‌های مرتبط
بهینه‌سازی درخواست‌ها و جلوگیری از بلاک‌شدن
1404-09-22
وب‌اسکریپینگ پایتون: عبور از ضدربات‌ها
این مقاله یک راهنمای عملی برای توسعه‌دهندگان پایتون دربارهٔ تکنیک‌های استیلث و دورزدن مکانیزم‌های ضداسکریپ ارائه می‌دهد؛ شامل بهینه‌سازی هدرها، پروکسی‌های چرخان، مرورگرهای headless، حل CAPTCHA و نکات حقوقی و عملی برای تولید یک اسکریپر پایدار و قابل‌اعتماد.
بهینه‌سازی درخواست‌ها و جلوگیری از بلاک‌شدن
1404-09-16
بازتلاش (Retry) درخواست‌ها در Java OkHttp برای وب اسکریپینگ
این مقاله دو راهکار عملی برای بازتلاش درخواست‌ها در Java OkHttp برای وب اسکریپینگ را نشان می‌دهد: استفاده از کتابخانهٔ Retry4j برای پیکربندی سریع و قابل‌تنظیم، و نوشتن wrapper سفارشی برای کنترل دقیق‌تر (شامل بررسی HTML با Jsoup). نکات عملی دربارهٔ backoff، timeouts، امنیت و بهترین روش‌ها نیز ارائه شده است.
بهینه‌سازی درخواست‌ها و جلوگیری از بلاک‌شدن
1404-09-15
اسکریپ با Java: تنظیم و چرخش User-Agent در OkHttp و Apache HttpClient
این مقاله نشان می‌دهد چگونه در Java با OkHttp و Apache HttpClient هدرهای User-Agent و مجموعه هدرهای مرورگر را تنظیم و بچرخانید، چگونه با APIهای بیرونی هزاران User-Agent را مدیریت کنید و بهترین شیوه‌های امنیتی و عملکردی برای وب اسکریپینگ را پیاده‌سازی کنید.