مقدمه
در وب اسکریپینگ مدرن، بسیاری از صفحات دادهها را با جاوااسکریپت و فراخوانیهای AJAX بارگذاری میکنند؛ در نتیجه فقط درخواست HTTP ساده اغلب کافی نیست. برای گرفتن نسخهٔ نهاییِ رندرشدهٔ صفحه و اجرای اسکریپتهای سمت کلاینت باید از headless browser استفاده کنیم. در این مقالهٔ آموزشی که برای توسعهدهندههای پایتون سطح متوسط نوشته شده، انواع رایج headless browserهای Node.js (مثل Puppeteer و Playwright) معرفی میشوند، نمونههای کد عملی ارائه میشود و نکات عملکردی، امنیتی و بهترینروشها برای اجرای پایدار اسکریپها بررسی میشود.
چرا از headless browser استفاده کنیم
هدف اصلی استفاده از headless browser این است که صفحه را مثل یک مرورگر واقعی بارگذاری کنیم تا:
- تمام جاوااسکریپت اجرا شود و DOM نهایی در دسترس قرار گیرد.
- قابلیت تعامل (کلیک، تایپ، اسکرول) برای باز کردن محتواهای داینامیک فراهم شود.
- قابلیت گرفتن screenshot، بررسی کنسول و متریکهای بارگذاری مهیا شود.
موارد عملی که نیاز به headless دارند شامل بارگذاری محتوا پس از AJAX، کلیک برای «Load more»، ورود به حساب کاربری برای دسترسی به محتوای محدودشده، و عبور از برخی مکانیزمهای ضدربات است.
مقایسهٔ اجمالی و انتخاب بر اساس نیاز
در انتخاب ابزار باید بین سازگاری مرورگر، استفادهٔ منابع، میزان نگهداری پروژه و سادگی API توازن برقرار کنید. به صورت خلاصه:
- Puppeteer: بهترین گزینهٔ عمومی برای اسکریپ کردن صفحات پیچیده با Chrome/Chromium.
- Playwright: وقتی نیاز به تست یا اسکریپ کردن cross-browser (Chromium, Firefox, WebKit) دارید.
- ZombieJS و CasperJS: سبکتر ولی اغلب قدیمی و بدون پشتیبانی کامل از همهٔ ویژگیهای مدرن.
- Nightmare.js: API ساده و مناسب برای گردشهای ساده؛ ولی وابسته به Electron است و ممکن است سنگینتر یا کمتحرکتر باشد.
Puppeteer — معرفی و نمونه عملی
Puppeteer یک کتابخانهٔ Node.js از تیم Chromium است که کنترل کامل Chrome/Chromium را فراهم میکند. برای اسکریپ کردن صفحاتی که شدیداً به جاوااسکریپت وابستهاند اغلب اولین انتخاب است.
نصب (دستورات نصب باید در ترمینال اجرا شوند):
npm install puppeteerنمونهٔ عملی: باز کردن صفحه، انتظار تا بارگذاری کامل و استخراجِ متنِ همهٔ نقلقولها.
const puppeteer = require('puppeteer');
(async () => {
// ورودی: URL صفحه
const browser = await puppeteer.launch({ headless: true });
const page = await browser.newPage();
// تنظیم هدرها و user-agent برای بهبود شبیهسازی کاربر
await page.setUserAgent('Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 Chrome/90.0.0.0 Safari/537.36');
// رفتن به صفحه و منتظر ماندن تا شبکه تقریباً پایدار شود
await page.goto('https://quotes.toscrape.com/', { waitUntil: 'networkidle2', timeout: 30000 });
// خروجی: آرایهای از متن نقلقولها
const quotes = await page.evaluate(() => {
return Array.from(document.querySelectorAll('.quote > .text')).map(el => el.innerText.trim());
});
console.log(quotes);
await browser.close();
})();توضیح خطبهخط (خلاصه):
- ایمپورت puppeteer و راهاندازی تابع async برای کار با await.
- puppeteer.launch یک نمونهٔ Chromium را اجرا میکند؛ گزینهٔ headless تعیینکنندهٔ نمایش GUI است.
- page.setUserAgent برای تقلید مرورگر واقعی و کاهش احتمال شناسایی توسط برخی سرورها مفید است.
- page.goto با waitUntil: 'networkidle2' منتظر پایان درخواستهای شبکه میماند تا مطمئن شویم JS اجرا شده است.
- page.evaluate در کانتکست صفحه اجرا میشود و DOM نهایی را خوانده و آرایهٔ متنها را برمیگرداند.
نکات عملی و best practices برای Puppeteer:
- برای صرفهجویی در منابع، در حالتهای موازی از چندین پروسس یا cluster استفاده کنید (مثلاً puppeteer-cluster در اکوسیستم Node).
- برای سرعت بالاتر میتوانید درخواستهای تصاویر و فونت را بلاک کنید با page.setRequestInterception(true) و سپس فیلتر کردن نوع resource.
- برای سالم ماندن sessionها از ذخیره و بارگذاری کوکی و localStorage استفاده کنید.
- برای عبور از چکهای سادهٔ ضدبات از تغییر user-agent، زمانبندی تعاملات و human-like delays استفاده کنید؛ در موارد سختتر از پلاگینهای stealth بهره ببرید.
Playwright — چندمرورگر و کد نمونه
Playwright یک API یکپارچه فراهم میکند تا با Chromium، Firefox و WebKit کار کنید. اگر نیاز به اطمینان از کارکرد اسکریپ روی چند مرورگر دارید، Playwright انتخاب مناسبی است.
نصب (فرآیند نصب تعاملی ممکن است):
npm init playwright@latest
# یا: npm install playwright
# سپس برای نصب مرورگرها: npx playwright installنمونهٔ ساده: گرفتن عنوان صفحه با Playwright:
const { chromium } = require('playwright');
(async () => {
// ورودی: URL
const browser = await chromium.launch({ headless: true });
const context = await browser.newContext();
const page = await context.newPage();
await page.goto('https://quotes.toscrape.com/');
// خروجی: عنوان صفحه
const title = await page.title();
console.log('Title:', title);
await browser.close();
})();چرا Playwright؟
- قابلیت تست cross-browser با همان کد.
- Locatorهای قدرتمند و امکاناتی مثل ضبط ویدئو / ضبط شبکه برای دیباگینگ.
- امکانات بهتر برای اتوماسیون پیچیدهٔ تعاملات کاربر.
نکات عملی: در پروژههای بزرگ نصب و مدیریت مرورگرها و نگهداری نسخهها مهم است؛ Playwright این مسئله را با ابزارهای جانبی تا حدی حل میکند اما حجم نصبها بالاتر خواهد بود.
ZombieJS — سبک و سریع ولی محدود
ZombieJS یک محیط شبیهسازی DOM داخل Node است که بدون اجرای مرورگر واقعی صفحات را پردازش میکند. مناسب تستهای سریع و scenarioهای ساده است اما برای سایتهای پیچیدهٔ مدرن که به APIهای پیشرفتهٔ مرورگر نیاز دارند مناسب نیست.
نصب:
npm install zombieنمونهٔ استفادهٔ ساده:
const Browser = require('zombie');
Browser.visit('https://quotes.toscrape.com/', {}, function(error, browser) {
if (error) { console.error(error); return; }
const quotesEl = browser.document.querySelectorAll('.quote > .text');
const quotes = [];
quotesEl.forEach(el => quotes.push(el.textContent.trim()));
console.log(quotes);
});ملاحظات:
- Zombie سریع است اما موتور جاوااسکریپت و رندر آن کامل نیست و ممکن است DOM نهاییِ صفحههای پیچیده را بهدرستی تولید نکند.
- پروژهها و مستندات ممکن است بهروز نباشند؛ قبل از استفاده در تولید بررسی کنید.
CasperJS — اسکریپتینگ ناوبری قدیمی
CasperJS روی PhantomJS یا SlimerJS سوار میشد و برای اسکریپت کردن سناریوهای ناوبری و گرفتن اسکرینشات مناسب بود. امروزه PhantomJS عملاً منسوخ شده و CasperJS دیگر گزینهٔ بهروز و توصیهشدهای برای پروژههای جدید نیست، مگر برای نگهداریِ کد قدیمی.
نمونهٔ نوشتن سادهٔ سناریو:
// مثال شبهکد (CasperJS)
casper.start('https://quotes.toscrape.com/');
casper.then(function() {
// عملیات بعد از لود صفحه
});
casper.thenClick('#submit', function() {
// بعد از کلیک
});
casper.then(function() {
this.capture('screen.png');
});
casper.run();هشدار: اگر با نیازهای مدرن مثل WebKit جدید یا ویژگیهای ES6 سر و کار دارید، بهتر است از Playwright یا Puppeteer استفاده کنید.
Nightmare.js — API ساده مبتنی بر Electron
Nightmare.js برای گردشهای سادهٔ اتوماسیون مناسب است و از Electron استفاده میکند. API زنجیرهای آن برای خوانایی خوب است اما وابستگی به Electron باعث افزایش حجم و گاهی پیچیدگی محیط نصب میشود.
نصب و نمونه:
npm i nightmareconst Nightmare = require('nightmare');
const nightmare = Nightmare({ show: false });
nightmare
.goto('https://quotes.toscrape.com/')
.evaluate(() => Array.from(document.querySelectorAll('.quote > .text')).map(e => e.innerText))
.end()
.then(console.log)
.catch(error => console.error('Scraping failed:', error));نکات: مناسب اسکریپهای قابلفهم و سریع برای گردشهای ساده است؛ برای پروژههای بزرگ با نیاز به همزمانی و مقیاسپذیری، ممکن است گزینهٔ ضعیفتری باشد.
نکات تخصصی برای اجرای پایدار وب اسکریپینگ
برای ساختن اسکریپرهای قابلاعتماد، به چند بخش توجه کنید:
- مدیریت منابع: اجرای همزمانِ تعداد زیادی browser instance میتواند حافظه و CPU را اشغال کند؛ از روشهایی مثل pool یا cluster استفاده کنید.
- پروکسی و IP Rotation: برای جلوگیری از بلاک شدن از پراکسیهای چرخشی یا سرویس proxy pool استفاده کنید و برای هر session IP را تغییر دهید.
- هدرها و تایمینگ: user-agent، ریفرِر و زمانبندی تعاملها را شبیه رفتار انسانی تنظیم کنید — درخواستها را با تأخیرهای تصادفی ارسال کنید.
- retry و backoff: برای خطاهای موقتی از retries با exponential backoff استفاده کنید و تعداد تلاشها را محدود کنید.
- کاهش بار شبکه: درخواستهای غیرضروری مثل تصاویر یا فونت را مسدود کنید تا سرعت و مصرف منابع کاهش یابد.
- ذخیرهٔ session: کوکیها و localStorage را ذخیره و بارگذاری کنید تا نیازی به لاگین مکرر نباشد.
- مانیتورینگ و لاگینگ: خطاها، زمان پاسخ و نرخ موفقیت را مانیتور کنید تا رفتار اسکریپر در طول زمان قابل تحلیل باشد.
- مسائل حقوقی و اخلاقی: مطمئن شوید قوانین سایت و robots.txt را رعایت میکنید و از حجم درخواستهای بالا که سرویسها را مختل میکند خودداری نمائید.
نمونهٔ جریان کاری عملی (workflow) برای جمعآوری داده
یک pipeline ساده و مؤثر برای اسکریپ کردن چند صفحه:
- صفشدن URLها در یک صف خروجی (مثلاً Redis یا یک دیتابیس)،
- گرفتن یک آیتم از صف و اختصاص آن به یک worker،
- در worker: راهاندازی instance درون یک pool، باز کردن صفحه با waitUntil: 'networkidle2'، استخراج دادهها با evaluate و ذخیرهٔ نتیجه،
- در صورت خطا: ریتری با backoff، و بعد از چند تلاش ناموفق، ثبت به عنوان failed و ادامه به آیتم بعدی،
- پاکسازی منابع و بازگرداندن instance به pool.
جمعبندی
خلاصهٔ عملی: اگر هدف شما اسکریپ کردن صفحات پیچیدهٔ مبتنی بر JavaScript و داشتن کنترل دقیق روی مرورگر است، Puppeteer گزینهٔ اول است؛ اگر بخواهید روی چند موتور مرورگر تست و اجرا کنید، Playwright ارزش سرمایهگذاری دارد. ابزارهای سبکتر مثل ZombieJS یا قدیمیتر مثل CasperJS و Nightmare.js در سناریوهای خاص کاربرد دارند اما برای پروژههای جدید با نیاز به پایداری و پشتیبانی بلندمدت بهتر است به Puppeteer یا Playwright فکر کنید.
در نهایت روی سازوکارهای مقیاسپذیری (pooling/queue)، مدیریت پروکسی، retry منطقی و لاگینگ تمرکز کنید تا اسکریپهای شما هم سریع و هم قابلاطمینان باشند.





