در بسیاری از سایتهای مدرن، View Source تقریباً خالی است اما در مرورگر پر از محصول و قیمت میبینید. دلیلش رندر JavaScript است: HTML اولیه فقط اسکلت است و داده بعد از اجرای JS در DOM مینشیند. برای استخراج داده از وب در این حالت، Playwright مرورگر headless را کنترل میکند.
- HTML اولیه ≠ آنچه کاربر میبیند
- Playwright = مرورگر واقعی + API اتوماسیون
- wait strategy مهمتر از سرعت خام
- گاهی intercept Network از parse DOM بهتر است
چرا HTML اولیه کامل نیست؟
SPA (React/Vue) داده را با fetch میگیرد و در client رندر میکند. سرور ممکن است فقط <div id="app"></div> بدهد. Requests+BeautifulSoup روی همان پاسخ، قیمت را نمیبیند.
JavaScript rendering و DOM
مرورگر JS را اجرا میکند، DOM درختی ساخته میشود و ممکن است چند بار mutate شود. Scraper شما باید بعد از این فاز query بزند — نه روی HTML خام.
Playwright چه میکند؟
Chromium/Firefox/WebKit را launch میکند، browser context (cookie، viewport) میسازد، صفحه را باز میکند و با locator روی DOM کار میکند. Auto-wait تا element آماده شود صبر میکند.
Wait strategy
wait_for_selector— وقتی عنصر محصول ظاهر شدwait_until=domcontentloaded— سبکتر از networkidleexpect_response— منتظر API لیست محصول
Network requests
در DevTools ببینید آیا لیست از XHR میآید. intercept همان JSON اغلب پایدارتر از scrape کارت HTML است — با همان session و احراز هویت مرورگر در صورت نیاز.
انتخابگر، ورود، صفحهبندی
selector پایدار ترجیحاً data-*. session در context نگه دارید. pagination و infinite scroll در مقاله صفحهبندی.
Headless
بدون UI سریعتر است؛ بعضی سایتها headless را تشخیص میدهند — throttle و رفتار منطقی مهمتر از مخفیکاری است.
چه زمانی Playwright لازم نیست؟
داده در HTML اولیه یا API رسمی. اول API در برابر Scraping را بررسی کنید.
محدودیتها: سرعت، حافظه، پیچیدگی
هر browser context دهها تا صدها مگابایت RAM میگیرد؛ ۵۰ tab همزمان روی یک VPS کوچک معمولاً به swap و crash میخورد. pool worker محدود (مثلاً ۳–۵ context) و reuse context برای چند URL منطقیتر از launch برای هر لینک است.
سرعت: رندر JS + wait از یک GET ساده کندتر است — برای هزاران URL فقط وقتی Playwright لازم است استفاده کنید. deploy نیاز به dependency مرورگر و در Linux گاهی کتابخانههای سیستمی دارد. selector شکننده = هزینه نگهداری مداوم؛ ترجیح data-testid / API شبکه.
from playwright.sync_api import sync_playwright
with sync_playwright() as p:
browser = p.chromium.launch(headless=True)
page = browser.new_context(locale="fa-IR").new_page()
page.goto("https://example.com/shop", wait_until="domcontentloaded")
page.wait_for_selector("[data-product-id]")
for node in page.locator("[data-product-id]").all():
print(node.get_attribute("data-product-id"))
browser.close()
در عمل چه انتخابی کنیم؟
اگر در Network endpoint JSON لیست دارید و مجازید → API. اگر فقط UI → Playwright با wait مشخص و pool محدود worker. برای مقایسه ابزار مرورگر: Playwright یا Selenium. پیادهسازی: Scraper اختصاصی.