ویرگول
ورودثبت نام
رامتین قبادی
رامتین قبادیرامتین قبادی هستم. در حدود ۱۷ سال هست در حوزه نرم افزار کار میکنم . دوست دارم در محیط ویرگول یکسری مطالب آموزشی منتشر کنم.
رامتین قبادی
رامتین قبادی
خواندن ۳ دقیقه·۱۳ ساعت پیش

ساخت یک مرورگر Headless بخش اول

مرورگرهای Headless در سال‌های اخیر به یکی از ابزارهای اصلی توسعه‌دهندگان تبدیل شده‌اند. این نوع مرورگرها بدون رابط گرافیکی اجرا می‌شوند و امکاناتی مانند رندر صفحات وب، اجرای جاوااسکریپت، پیمایش، اسکرین‌شات و تعامل با DOM را در اختیار برنامه‌های سمت سرور قرار می‌دهند. در این مقاله، نحوه ساخت یک مرورگر Headless ساده با استفاده از زبان Go و کتابخانه Chromedp بررسی می‌شود و در نهایت یک API کاربردی برای گرفتن اسکرین‌شات ارائه خواهد شد.

در اصل پیش زمینه ای برای ساختن مرورگرهای ابری روی سرور فراهم میآورند و بدون داشتن صفحه مرورگر اطلاعات وب سایت و ... را پردازش میکنند.

۱. معرفی Chromedp

کتابخانهٔ Chromedp یک ابزار قدرتمند برای تعامل برنامه‌نویسی با مرورگر Google Chrome از طریق Chrome DevTools Protocol است. این کتابخانه امکان انجام عملیات‌هایی مانند موارد زیر را فراهم می‌کند:

  • باز کردن صفحات وب

  • اجرای اسکریپت‌های جاوااسکریپت

  • استخراج داده از DOM

  • اسکرول، کلیک و شبیه‌سازی رفتار کاربر

  • گرفتن اسکرین‌شات در اندازه کامل یا بخش خاصی از صفحه

  • تبدیل صفحه به PDF

Chromedp کاملاً در Go نوشته شده و نیاز به نصب selenium یا webdriver ندارد.

۲. ساخت ساختار اصلی مرورگر

برای مدیریت یک مرورگر Headless ابتدا یک ساختار معرفی می‌شود که context و تابع لغو (cancel) را نگه‌داری می‌کند:

type BrowserInstance struct { ctx context.Context cancel context.CancelFunc }

وظیفه‌ی این ساختار

  • ctx مسئول نگه‌داری اطلاعات Session مرورگر و کانال ارتباطی با DevTools است.

  • cancel امکان متوقف‌سازی و آزادسازی منابع مرورگر را فراهم می‌کند.

۳. ایجاد یک نمونه از مرورگر

با استفاده از تابع chromedp.NewContext یک مرورگر Headless ساخته می‌شود:

func NewBrowserInstance() (*BrowserInstance, error) { ctx, cancel := chromedp.NewContext(context.Background()) return &BrowserInstance{ ctx: ctx, cancel: cancel, }, nil }

مراحل انجام‌شده در این تابع

  1. ساخت context پایه (context.Background)

  2. ساخت context اختصاصی مرورگر و آغاز به‌کار Chrome Headless

  3. بازگرداندن ساختار مدیریت‌کننده مرورگر

۴. بارگذاری یک URL در مرورگر

برای باز کردن یک آدرس اینترنتی از تابع زیر استفاده می‌شود:

func (b *BrowserInstance) LoadURL(url string) error { err := chromedp.Run(b.ctx, chromedp.Navigate(url), chromedp.WaitReady("body", chromedp.ByQuery), ) return err }

توضیح مراحل

  • Navigate آدرس موردنظر را در مرورگر باز می‌کند.

  • WaitReady تا زمانی که تگ <body> آماده باشد صبر می‌کند و از رندر کامل محتوای صفحه مطمئن می‌شود.

۵. گرفتن اسکرین‌شات از صفحه

تابع زیر محتوای صفحه را به‌صورت PNG باز می‌گرداند:

func (b *BrowserInstance) Screenshot() ([]byte, error) { var buf []byte err := chromedp.Run(b.ctx, chromedp.CaptureScreenshot(&buf), chromedp.Sleep(500*time.Millisecond), ) return buf, err }

نکات

  • CaptureScreenshot تصویر کامل صفحه را گرفته و در متغیر buf ذخیره می‌کند.

  • Sleep برای اطمینان از رندر کامل عناصر پویا استفاده می‌شود.

۶. ساخت یک API برای دریافت اسکرین‌شات

در این مرحله یک هندلر HTTP معرفی می‌شود که با گرفتن یک URL از کاربر، تصویر صفحه را بازگردانی می‌کند.

کد Handler:

func screenshotHandler(w http.ResponseWriter, r *http.Request) { url := r.URL.Query().Get("url") if url == "" { http.Error(w, "url is required", http.StatusBadRequest) return } browser, err := NewBrowserInstance() if err != nil { http.Error(w, "failed to create browser", http.StatusInternalServerError) return } defer browser.Close() if err := browser.LoadURL(url); err != nil { http.Error(w, "failed to load url", http.StatusInternalServerError) return } img, err := browser.Screenshot() if err != nil { http.Error(w, "failed to capture screenshot", http.StatusInternalServerError) return } w.Header().Set("Content-Type", "image/png") w.Write(img) }

۷. اجرای سرور

func main() { http.HandleFunc("/screenshot", screenshotHandler) fmt.Println("Server running at :8081") http.ListenAndServe(":8081", nil) }

۸. نحوهٔ استفاده

پس از اجرای برنامه:

http://localhost:8081/screenshot?url=https://example.com

مرورگر Headless:

  1. صفحهٔ example.com را باز می‌کند

  2. آن را کامل رندر می‌کند.

  3. یک تصویر PNG بازمی‌گرداند

در بخش بعدی به توسعه کامل تر میپردازیم و کدهای نوشته شده در یک مخزن گیت نگهداری میکنیم.

golanggocontext
۱
۰
رامتین قبادی
رامتین قبادی
رامتین قبادی هستم. در حدود ۱۷ سال هست در حوزه نرم افزار کار میکنم . دوست دارم در محیط ویرگول یکسری مطالب آموزشی منتشر کنم.
شاید از این پست‌ها خوشتان بیاید