

وقتی با وباپهای پویا کار میکنیم، محتوای صفحه معمولاً از طریق درخواستهای پسزمینه (XHR یا Fetch) از سرور بارگذاری میشود. در وب اسکریپینگ، گرفتن این درخواستها میتواند به شما کمک کند دادهٔ خام API را مستقیم دریافت کنید، نقطهنظارت روی ترافیک بسازید یا حتی برخی درخواستها را مسدود و رفتار سایت را آزمایش کنید. در انتهای این مقاله شما میآموزید چگونه با Playwright درخواستهای XHR/Fetch را ضبط کنید، آنها را تحلیل کنید، درخواستها را مسدود یا تغییر دهید و نتایج را برای استفادهٔ بعدی بازپخش (replay) کنید.
پیش از ورود به کد لازم است تفاوتهای پایهای روشهای HTTP را بدانیم، چون در تحلیل درخواستها معمولاً به GET, POST, PUT و DELETE برمیخوریم:
در عمل، بسیاری از وباپها از XHR/Fetch برای بارگذاری مقادیر JSON یا ارسال فرمها استفاده میکنند؛ ضبط این درخواستها میتواند به شما امکان دسترسی مستقیم به APIها را بدهد و گاهی نیاز به اسکریپ کردن HTML را از بین ببرد.
در این بخش یک نمونهٔ عملی Python با playwright.async_api میبینیم که روی رخدادهای درخواست گوش میدهد و فقط درخواستهای xhr و fetch را ثبت میکند.
from playwright.async_api import async_playwright
import asyncio
async def scrape(url):
async with async_playwright() as pw:
browser = await pw.chromium.launch(headless=True) # ورودی: headless یا headful
page = await browser.new_page() # خروجی: یک شیٔ Page برای تعامل
def on_request(request):
# نقش: فیلتر کردن درخواستها بر اساس نوع (xhr / fetch)
if request.resource_type in ("xhr", "fetch"):
# request.url : آدرس درخواست
# request.method : متد HTTP
print("Captured:", request.url, request.method)
# اتصال شنونده وقوع درخواست به صفحه
page.on("request", on_request)
await page.goto(url) # ناوبری به سایت هدف
await asyncio.sleep(5) # اجازه بدهیم پسزمینه فعالیت کند
await browser.close() # بستن مرورگر
# اجرای تابع اصلی
asyncio.run(scrape('https://example.com'))توضیح خطبهخط:
گاهی میخواهیم آماری داشته باشیم: چند GET، POST و ... رخ داده است؛ برای جلوگیری از محدودیتهای دامنهٔ اسکوپِ توابع، از ساختار دادهٔ تغییرپذیر استفاده میکنیم.
from playwright.async_api import async_playwright
import asyncio
async def scrape_counts(url):
counts = {"GET": 0, "POST": 0, "PUT": 0, "DELETE": 0}
async with async_playwright() as pw:
browser = await pw.chromium.launch(headless=True)
page = await browser.new_page()
def on_request(request):
if request.resource_type in ("xhr", "fetch"):
method = request.method
if method in counts:
counts[method] += 1
page.on("request", on_request)
await page.goto(url)
await asyncio.sleep(5)
await browser.close()
print("Counts:", counts)
asyncio.run(scrape_counts('https://example.com'))خروجی: یک دیکشنری که تعداد هر متد را نشان میدهد — مفید برای فهم الگوی ترافیک و تصمیمگیری دربارهٔ بازپخش یا مسدودسازی برخی متدها.
اگر بخواهید نه تنها مشاهده بلکه درخواست را مسدود یا تغییر دهید، از page.route استفاده کنید. در مثال زیر درخواستهای POST از نوع XHR/Fetch را میبندیم (abort) و بقیه را اجازه میدهیم ادامه پیدا کنند.
import asyncio
from playwright.async_api import async_playwright
async def scrape_block_posts(url):
counts = {"GET": 0, "Blocked_POST": 0}
async with async_playwright() as pw:
browser = await pw.chromium.launch(headless=True)
page = await browser.new_page()
async def handler(route, request):
# همهٔ مسیرها را میگیریم و تصمیم میگیریم
if request.resource_type in ("xhr", "fetch") and request.method == "POST":
await route.abort() # جلوگیری از ارسال به سرور
counts["Blocked_POST"] += 1
else:
await route.continue_() # آزاد کردن درخواست
# ثبت route: الگوی "**/*" همه منابع را میگیرد
await page.route("**/*", handler)
await page.goto(url)
await asyncio.sleep(5)
await browser.close()
print(counts)
asyncio.run(scrape_block_posts('https://example.com'))نکات خطبهخط:
برای کسانی که با Node.js کار میکنند، منطق مشابه است. این نمونهٔ سادهٔ JavaScript همان رفتار گوشدادن به request را نشان میدهد:
const playwright = require('playwright');
(async () => {
const browser = await playwright.chromium.launch({ headless: true });
const page = await browser.newPage();
page.on('request', request => {
if (request.resourceType() === 'xhr' || request.resourceType() === 'fetch') {
console.log('Captured', request.method(), request.url());
}
});
await page.goto('https://example.com');
await page.waitForTimeout(5000);
await browser.close();
})();پس از ضبط، اغلب میخواهیم یک درخواست خاص را بازپخش کنیم (مثلاً برای دانلود JSON یا ساخت یک API client). برای این کار میتوان اطلاعات زیر را ذخیره کرد:
نمونهٔ بازپخش با کتابخانهٔ requests در پایتون:
import requests
# ورودیها: url، headers، payload که از Playwright ذخیره شدهاند
resp = requests.post(url, headers=headers, data=payload, timeout=10)
print(resp.status_code, resp.text[:500]) # خروجی: وضعیت و بخشی از پاسخنکته: هنگام بازپخش حتماً هدرهای لازم (مثلاً توکنهای احراز هویت یا کوکی) را منتقل کنید تا درخواست مشابهِ کلاینت اصلی رفتار کند.
در عمل با چند چالش معمول روبهرو میشویم:
ضبط و تحلیل درخواستهای XHR/Fetch با Playwright یک ابزار قدرتمند در وب اسکریپینگ است: هم برای کشف APIها و هم برای بهینهسازی اسکریپها. با ترکیب page.on برای مانیتورینگ و page.route برای کنترل/مسدودسازی میتوانید جریان شبکه را به دقت مدیریت کنید. رعایت نکات async، مدیریت هدرها و استفاده از پراکسی/سیاستهای مناسب، عملکرد و پایداری کارتان را بالا میبرد—حالا وقتش است که یک اسکریپ میسازید و آن را بهبود میدهید.