مقدمه
در وب اسکریپینگ با مرورگرهای خودکار مثل Playwright، بارگذاری کامل همهٔ منابع (تصاویر، CSS، اسکریپتها، XHR و…) میتواند سرعت و هزینهٔ عملیات را بسیار بالا ببرد. در این مقاله قدمبهقدم یاد میگیریم چطور با هدف بهبود عملکرد و پایداری، منابع غیرضروری را در Playwright مسدود کنیم و تنها دادهٔ مورد نیاز را بارگیری کنیم.
بعد از خواندن این مطلب شما میتوانید: تنظیمات پایهٔ page.route را بنویسید، انواع منابع را شناسایی و مسدود کنید، موارد لِیزیلود و محتوای داینامیک را مدیریت کنید، و نکات عملکرد/امنیت هنگام بلاک کردن منابع را رعایت کنید.
درک پایه: ابزارهای Playwright برای کنترل درخواستها
سه متد اصلی که در این راهنما مرتب از آنها استفاده میکنیم عبارتاند از: page.route برای رهگیری مسیرها، request.resourceType() برای تشخیص نوع منبع، و route.abort/route.continue برای متوقف یا اجازه دادن به درخواستها. رفتار کلی این است که ابتدا برای یک الگوی مسیر (مثلاً "**/*") یک هندلر تعریف میکنیم و سپس بر اساس resourceType() تصمیم میگیریم که درخواست را رد کنیم یا بگذرانیم.
مثال سریع (TL;DR) — بلاک تمام منابع غیرضروری
مثال زیر نسخهٔ سریع و عملیاتی است که تصاویر، استایلها، مدیا، اسکریپتها و درخواستهای XHR/Fetch را مسدود میکند. این کد ورودی: یک آرایهٔ آدرس یا یک URL است؛ خروجی: اسکرینشات صفحهٔ بارگذاریشده بدون منابع مسدودشده و بسته شدن مرورگر.
const playwright = require('playwright');
async function scrapeData(url) {
const browser = await playwright.chromium.launch({ headless: true });
const page = await browser.newPage();
// رهگیری همهٔ درخواستها
await page.route('**/*', (route, request) => {
const type = request.resourceType();
if (type === 'image' || type === 'stylesheet' || type === 'media' || type === 'script' || type === 'xhr' || type === 'fetch') {
// مسدود کردن منابع غیرضروری
route.abort();
} else {
route.continue();
}
});
await page.goto(url, { waitUntil: 'domcontentloaded' });
await page.screenshot({ path: 'noResources.png', fullPage: true });
await browser.close();
}
scrapeData('https://example.com');توضیح خطها (خلاصه):
- require('playwright'): بارگذاری کتابخانه Playwright.
- playwright.chromium.launch: اجرای مرورگر Chromium؛ با headless: true معمولاً سریعتر است.
- page.route('**/*', handler): برای تمام درخواستها یک هندلر تعریف میکند.
- request.resourceType(): نوع منبع را برمیگرداند (مثل image، script، xhr و ...).
- route.abort() و route.continue(): به ترتیب رد یا اجازهٔ ادامهٔ درخواست.
بلاک کردن انواع منابع بهصورت جداگانه
در ادامه نمونههای کوچکتری میبینید و برای هرکدام ورودیها/خروجیها و نکات مهم توضیح داده شدهاند.
بلاک تصاویر
// تنها تصاویر را بلاک میکند
await page.route('**/*', (route, request) => {
if (request.resourceType() === 'image') route.abort();
else route.continue();
});ورودی: درخواستهای شبکه؛ خروجی: جلوگیری از دانلود بایتهای مربوط به تصاویر. کاربرد: زمانی که تصویر برای استخراج دیتا لازم نیست.
بلاک CSS (استایلها)
await page.route('**/*', (route, request) => {
if (request.resourceType() === 'stylesheet') route.abort();
else route.continue();
});نکته: حذف CSS ممکن است باعث تغییر ساختار DOMِ رندرشده شود؛ اگر ساختار صفحه برای انتخابگرها اهمیت دارد مراقب باشید.
بلاک مدیا (صوت/ویدیو)
await page.route('**/*', (route, request) => {
if (request.resourceType() === 'media') route.abort();
else route.continue();
});بلاک اسکریپتها
await page.route('**/*', (route, request) => {
if (request.resourceType() === 'script') route.abort();
else route.continue();
});هشدار مهم: اگر محتوای هدف از طریق JavaScript بارگذاری میشود، بلاک کردن script باعث از کار افتادن آن خواهد شد و دادهٔ مورد نظر را از دست میدهید.
بلاک XHR و Fetch
await page.route('**/*', (route, request) => {
const t = request.resourceType();
if (t === 'xhr' || t === 'fetch') route.abort();
else route.continue();
});این باعث جلوگیری از فراخوانی APIهای فرانتاند میشود؛ اگر دادهها مستقیماً از XHR/fetch میآیند، نباید آنها را بلاک کنید.
موارد خاص و لِیزیلود (Handling Edge Cases)
برخی تصاویر و محتواها عملاً با JavaScript لِیزیلود میشوند یا آدرسهای آنها بعد از اجرای اسکریپت ساخته میشود. اگر فقط تصاویر را بلاک کنید اما اسکریپت اجازهٔ لِیزیلود را صادر کند، ممکن است باز هم درخواستهایی ایجاد شوند. برای چنین مواردی معمولاً دو راه وجود دارد:
- بلاک همزمان اسکریپتها و تصاویر (در صورتی که محتوای هدف داینامیک نباشد).
- استفاده از شرطهای پیچیدهتر روی request.url() یا هِدِرها تا فقط برخی منابع مسدود شوند.
مثال شرطی: تنها تصاویر با URLِ حاوی کلمهٔ "premium" را بلاک کن
await page.route('**/*', (route, request) => {
if (request.resourceType() === 'image' && request.url().includes('premium')) {
route.abort();
} else {
route.continue();
}
});رعایت کنید که request.url() در زمان درخواست در دسترس است و میتوان روی آن فیلتر نوشت.
آزمون، دیباگ و لاگگیری
برای اطمینان از اینکه فیلترها درست کار میکنند از دو روش استفاده کنید:
- اسکرینشات گرفتن: اگر تصاویر مسدود شده باشند، خروجی تصویری بدون عکس خواهد بود.
- لاگ شبکه: با page.on('request') و page.on('response') میتوانید رفتار درخواستها را ثبت کنید و علت بلوک شدن را ببینید.
page.on('request', req => console.log('REQ:', req.method(), req.url(), req.resourceType()));
page.on('response', res => console.log('RES:', res.status(), res.url()));
page.on('requestfailed', failure => console.log('FAILED:', failure.url(), failure.failure()));همچنین آزمون اتوماتیک میتواند شامل مقایسهٔ زمان اجرا (با console.time/ console.timeEnd) یا مقایسهٔ سایز نتایج خروجی باشد.
کاربردهای واقعی و معیارهای عملکرد
یک سناریوی رایج: پیمایش فهرستی از URLها. با مسدود کردن تصاویر و اسکریپتها میتوان زمان هر صفحه را بهطور قابلتوجهی کاهش داد. در مثال منبع، کاهشِ نزدیک به 20% گزارش شده است که در پردازشهای گسترده بسیار ارزشمند است.
const urls = ['https://quotes.toscrape.com', 'https://example.com', 'https://another.example'];
console.time('scrape');
for (let u of urls) {
await page.goto(u, { waitUntil: 'domcontentloaded' });
}
console.timeEnd('scrape');توجه: برای اسکریپهای همزمان (concurrent) بهتر است از چند context یا pool از مرورگرها استفاده کنید و محدودیتهای حافظه/CPU را مدنظر داشته باشید.
بهترینروشها و نکات امنیتی
- قبل از مسدود کردن script یا xhr مطمئن شوید دادهٔ هدف با این منابع وابسته نیست.
- از شرطهای دقیق (URL، هِدِر یا referer) برای جلوگیری از بلاککردن اشتباه استفاده کنید.
- از headless برای بهبود عملکرد و مصرف منابع استفاده کنید اما در هنگام اشکالزدایی از headful استفاده کنید تا DOM و رندر را بهتر ببینید.
- برای پایداری طولانیمدت از مکانیزمهای retry و backoff در برابر خطاهای شبکه استفاده کنید و درخواستهای ردشده را لاگ کنید.
- در عملیات در مقیاس بالا به محدودیتهای سایتها (rate limit، CAPTCHA و قوانین سرویس) احترام بگذارید و از پراکسی/تاخیر زمانی مناسب استفاده کنید.
جمعبندی
مسدود کردن منابع در Playwright با استفاده از page.route و request.resourceType() ابزار قدرتمندی برای بهبود سرعت و کاهش مصرف منابع در وب اسکریپینگ است. اما باید هوشمندانه و با آگاهی از وابستگیهای صفحه عمل کنید: گاهی بلاک کردن اسکریپتها یا XHR موجب از دست رفتن دادهٔ هدف میشود. با تست، لاگگیری و شرطگذاری دقیق میتوانید بهترین توازن بین سرعت و درستی را پیدا کنید.
شروع کنید با یک بلاککن ساده (مثلاً تصاویر) و بهتدریج شروط پیچیدهتر (URL، هدرها، یا whitelist/blacklist) اضافه کنید تا اسکریپ شما سریعتر و پایدارتر اجرا شود.





