وباسکرپینگ ابزاری ضروری برای مهندسان داده، پژوهشگران و توسعهدهندگانی است که نیاز به جمعآوری دادههای عمومی از وب دارند. در حالی که زبانهایی مانند پایتون با کتابخانههایی مانند BeautifulSoup و Scrapy در این حوزه پیشرو هستند، Go (Golang) جایگزینی جذاب برای توسعهدهندگانی است که عملکرد، همزمانی و ایمنی نوع را در اولویت قرار میدهند. گوروتینهای سبک و مدیریت حافظه کارآمد Go، آن را برای اسکرپینگ حجم بالای دادهها بهطور همزمان بدون بار اضافی مربوط به نخها (threading) که در سایر زبانها وجود دارد، بسیار مناسب میسازد.
در این راهنما، ما یک وباسکرپر عملی با استفاده از Go میسازیم. تمرکز ما بر استفاده از Colly، یک چارچوب وباسکرپینگ با عملکرد بالا برای Go است که تجزیه HTML، استخراج لینکها و مدیریت رویدادها را ساده میکند. در پایان این مقاله، شما درک محکمی از نحوه ساختاردهی یک اسکریپر، مدیریت درخواستهای ناهمگام و مدیریت چرخه حیات یک کار اسکرپینگ خواهید داشت.
چرا برای وباسکرپینگ Go را انتخاب کنیم؟
قبل از غرق شدن در کد، درک این موضوع ضروری است که چرا Go گزینهی قوی برای وظایف اسکرپینگ است. اول، Go به یک باینری واحد کامپایل میشود که استقرار آن را در محیطهای مختلف (لینوکس، macOS، ویندوز) بدون مشکل میسازد. دوم، اصول همزمانی داخلی زبان به شما اجازه میدهد تا درخواستها را بهطور کارآمد توزیع کنید. اگر نیاز به اسکرپینگ ۱۰۰۰ صفحه دارید، Go میتواند هزاران درخواست همزمان را با حداقل ردپای حافظه مدیریت کند، در حالی که پایتون ممکن است مگر اینکه با کتابخانههای ناهمگام به شدت پچ شود، با محدودیتهای قفل تفسیر جهانی (GIL) دستوپنج نرم کند.
راهاندازی پروژه
برای شروع، مطمئن شوید که Go روی سیستم شما نصب است. ما یک دایرکتوری پروژه جدید ایجاد کرده و ماژول Go را راهاندازی میکنیم. سپس، کتابخانه Colly را نصب میکنیم که یک API تمیز برای تعریف منطق اسکرپینگ ارائه میدهد.
mkdir go-scraper
cd go-scraper
go mod init go-scraper
go get -u github.com/gocolly/colly/v2
ساخت اسکریپر
ما اسکریپری میسازیم که به یک وبسایت هدف سر میزند، تمام لینکهای مقالات را از صفحه اصلی استخراج میکند و سپس هر مقاله را برای استخراج عنوان و محتوا بازدید میکند. این مثال مفاهیم اصلی را نشان میدهد: بازدید از URLها، استخراج دادهها با استفاده از انتخابگرهای CSS و مدیریت همزمانی.
package main
import (
"fmt"
"log"
"github.com/gocolly/colly/v2"
)
func main() {
// ایجاد یک نمونه Collector جدید
c := colly.NewCollector(
colly.AllowedDomains("example.com"), // محدود کردن به دامنههای مجاز
colly.UserAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64)"), // تنظیم User Agent
)
// برای هر عنصر a که دارای ویژگی href است، فراخوانی را انجام دهید
c.OnHTML("a[href]", func(e *colly.HTMLElement) {
link := e.Attr("href")
// بازدید از لینک یافت شده در آن صفحه
// لینکهای نسبی با استفاده از URI فعلی حل خواهند شد
c.Visit(e.Request.AbsoluteURL(link))
})
// برای هر لینک با کلاس "article-title"
c.OnHTML(".article-title", func(e *colly.HTMLElement) {
fmt.Printf("Found article: %s\n", e.Text)
})
// شروع اسکرپینگ روی example.com
if err := c.Visit("https://example.com"); err != nil {
log.Fatal(err)
}
}
در کد بالا، ما یک Collector را با گزینههای خاص مقداردهی اولیه میکنیم. گزینه AllowedDomains برای امنیت حیاتی است و اطمینان حاصل میکند که اسکریپر ما بهطور تصادفی به سایتهای مخرب یا نامرتبط ناوبری نمیکند. ما همچنین یک UserAgent را تنظیم میکنیم تا یک مرورگر واقعی را شبیهسازی کند که به جلوگیری از مسدود شدن فوری توسط مکانیسمهای ساده تشخیص ربات کمک میکند.
مدیریت همزمانی و محدودیت نرخ
یکی از مهمترین مزایای Go همزمانی است. با این حال، هنگام اسکرپینگ، احترام به بار سرور و سیاستهای ضد اسکرپینگ حیاتی است. Colly راههای آسانی برای مدیریت این موضوع ارائه میدهد.
شما میتوانید بازدیدهای موازی را با تنظیم colly.Async(true) فعال کنید، اما باید یک محدودکننده نرخ را نیز پیادهسازی کنید تا از غرق کردن سرور هدف جلوگیری کنید. در اینجا نحوه افزودن یک محدودکننده نرخ به Collector آورده شده است:
import "github.com/gocolly/colly/v2"
// افزودن یک محدودکننده نرخ: ۱ درخواست در ثانیه
c.Limit(&colly.LimitRule{
DomainGlob: "*",
Parallelism: 5,
Delay: 1 * time.Second,
})
این پیکربندی تضمین میکند که اسکریپر ما حداکثر ۵ درخواست در ثانیه با تأخیر ۱ ثانیهای بین آنها برای هر دامنه ارسال میکند. این کار نه تنها اخلاقی است، بلکه احتمال مسدود شدن آدرس IP شما را نیز کاهش میدهد.
تکنیکهای پیشرفته: مدیریت خطا و پشتیبانی از پروکسی
برای اسکریپرهای درجه تولید، مدیریت خطای مقاوم غیرقابل مذاکره است. Colly به شما اجازه میدهد فراخوانیهایی برای خطاها تعریف کنید که میتوانند مشکلات را ثبت کرده یا درخواستهای ناموفق را مجدداً تلاش کنند.
c.OnError(func(r *colly.Response, err error) {
log.Printf("Request URL: %s Failed with %s\n", r.Request.URL, err)
})
علاوه بر این، اگر با مسدود شدن IP مواجه شوید، میتوانید یک استخر پروکسی را پیادهسازی کنید. با چرخش پروکسیها، بار را توزیع کرده و دسترسی را حفظ میکنید. اگرچه پیادهسازی یک استخر پروکسی کامل فراتر از دامنه این پست مقدماتی است، اما یکپارچهسازی آن شامل پاس دادن یک تابع پروکسی به Collector در زمان مقداردهی اولیه است.
نتیجهگیری
ساخت وباسکریپرها در Go رویکردی قدرتمند برای توسعهدهندگانی است که به دنبال عملکرد و قابلیت اطمینان هستند. با بهرهگیری از Colly، میتوانید بخش زیادی از پیچیدگیهای مرتبط با درخواستهای HTTP و تجزیه HTML را انتزاع کنید و به شما امکان میدهد بر منطق استخراج داده متمرکز شوید. چه در حال جمعآوری دادههای بازار باشید، چه نظارت بر تغییرات قیمت یا انجام پژوهشهای آکادمیک، Go ابزارهای لازم را برای ساخت راهحلهای اسکرپینگ مقیاسپذیر، کارآمد و قابل نگهداری فراهم میکند.
هنگام گسترش اسکریپر خود، در نظر بگیرید که یکپارچهسازی پایگاه داده را برای ذخیره دادههای استخراج شده، پیادهسازی جریانهای احراز هویت پیچیدهتر یا استفاده از مرورگرهای بدون سر (headless) برای سایتهای سنگین جاوااسکریپت اضافه کنید. بنیانی که توسط Go و Colly گذاشته شده است، این مراحل بعدی را قابل مدیریت و کارآمد میسازد.