

اسکریپ صفحات و تعامل با المانها معمولاً نیاز دارد که آن المانها در نمای صفحه قابل مشاهده باشند. توانایی اسکرول کردن صفحه یکی از ابزارهای پایهای در جعبهابزار وب اسکریپینگ است—برای پیدا کردن عناصر، بارگذاری تصاویر lazy، گرفتن اسکرینشات یا شبیهسازی رفتار کاربر. در این راهنما، با متدهای مختلف اسکرول در Playwright آشنا میشویم، نمونهکدهای پایتون (async) و توضیحات خطبهخط میآوریم و نکات عملی دربارهٔ پایداری، کارآیی و امنیت را پوشش میدهیم.
ایدهٔ کلی: المان را پیدا کنید، آن را بهنمایش بیاورید (scroll into view) و سپس با آن تعامل کنید. مزیت این روش دقت بالا و مناسب بودن برای عناصر هدفمند است.
from playwright.async_api import async_playwright
async def scroll_to_element_and_click():
async with async_playwright() as p:
browser = await p.chromium.launch(headless=False)
page = await browser.new_page()
await page.goto('https://books.toscrape.com')
# ورودی: یک selector برای دکمه "next"
next_handle = await page.query_selector("text='next'")
if next_handle:
# اسکرول میکنیم تا عنصر دیده شود
await next_handle.scroll_into_view_if_needed()
# خروجی: کلیک روی دکمه (اگر قابل کلیک بود)
await page.wait_for_timeout(1000)
await next_handle.click()
await browser.close()
توضیح قدمبهقدم:
text='next').ایده: با window.scrollBy به اندازههای کوچک اسکرول کنیم و پس از هر گام بررسیکنیم آیا المان هدف قابل مشاهده شده یا خیر؛ این روش شبیه رفتار انسانی است و میتواند برای دور زدن برخی تشخیصهای بات مؤثر باشد.
# اسکرول مرحلهای تا پیدا شدن دکمه "next"
from playwright.async_api import async_playwright
async def step_scroll_until_visible():
async with async_playwright() as p:
browser = await p.chromium.launch(headless=False)
page = await browser.new_page()
await page.goto('https://books.toscrape.com')
max_iterations = 40
for _ in range(max_iterations):
# اسکرول به اندازهٔ 250 پیکسل
await page.evaluate('window.scrollBy(0, 250)')
await page.wait_for_timeout(500) # کمی معطل میکنیم تا محتوا بارگذاری شود
next_visible = await page.locator("text='next'").is_visible()
if next_visible:
await page.click("text='next'")
break
await browser.close()
نکات:
ایده: با یک اسکرولِ بزرگ (معمولاً document.body.scrollHeight) بلافاصله به انتهای صفحه برویم. سریع اما پرخطر از نظر شناسایی بهعنوان بات.
async def scroll_to_bottom_and_click():
async with async_playwright() as p:
browser = await p.chromium.launch()
page = await browser.new_page()
await page.goto('https://books.toscrape.com')
# اسکرول به پایین صفحه براساس ارتفاع سند
await page.evaluate('window.scrollBy(0, document.body.scrollHeight)')
await page.wait_for_timeout(500)
if await page.locator("text='next'").is_visible():
await page.click("text='next'")
await browser.close()
تذکر: این روش برای سایتهایی که از محافظت قوی استفاده نمیکنند مناسبتر است؛ در سایتهای حساس این کار میتواند رفتار رباتی را برجسته کند.
ایده: از API صفحهکلید Playwright استفاده کنید (مثلاً Space یا PageDown). این روش ساده اما غیرقابلپیشبینی است، چرا که میزان اسکرول در هر بار فشردن ممکن است متفاوت باشد.
async def keyboard_scroll_example():
async with async_playwright() as p:
browser = await p.chromium.launch(headless=False)
page = await browser.new_page()
await page.goto('https://books.toscrape.com')
for _ in range(6):
await page.keyboard.press('Space')
await page.wait_for_timeout(800)
await browser.close()
وقتی دقت مورد نیاز است، توصیه میشود از روشهای مبتنی بر جاوااسکریپت (scrollBy یا scrollIntoView) استفاده کنید.
ایده: شبیهسازی چرخ ماوس با page.mouse.wheel و حرکت نشانگر با page.mouse.move. برای شبیهسازی رفتار کاربر مفید است اما دقیق نیست.
async def mouse_wheel_scroll():
async with async_playwright() as p:
browser = await p.chromium.launch()
page = await browser.new_page()
await page.goto('https://books.toscrape.com')
# حرکت چرخ ماوس؛ Y مثبت یعنی اسکرول پایین
await page.mouse.wheel(0, 200)
await page.mouse.move(100, 200)
await page.wait_for_timeout(500)
await browser.close()
نکته: این روش ممکن است در مرورگرها یا درایورهای مختلف مقادیر متفاوتی اسکرول تولید کند؛ تست کراسبراؤزر ضروری است.
اگر هدف شما شبیهسازی دستگاه موبایل است، ساختن کانتکست با has_touch=True و استفاده از page.tap یا اسکرول با window.scrollBy ترکیب مناسبی است:
async def touchscreen_scroll():
async with async_playwright() as p:
browser = await p.chromium.launch()
context = await browser.new_context(has_touch=True)
page = await context.new_page()
await page.goto('https://books.toscrape.com')
# اسکرول کوچک شبیه سوایپ
await page.evaluate('window.scrollBy(0, 30)')
await page.wait_for_timeout(300)
# لمس/تپ روی دکمه
if await page.locator("text='next'").is_visible():
await page.tap("text='next'")
await browser.close()
نکتهٔ عملی: بعضی سایتها فقط وقتی رفتارهای لمسی واقعی ببینند بارگذاری ادامه پیدا میکند؛ تنظیم has_touch میتواند کمک کند.
وقتی دادهها هنگام اسکرول پویا بارگذاری میشوند، باید صبر و هماهنگی بین اسکرول و بارگذاری جدید برقرار کنید. دو رویکرد رایج:
سادگی دارد اما حساس به سرعت شبکه و تغییرات سایت است.
# مثال: اسکرول بزرگ سپس waitForTimeout
await page.evaluate('window.scrollBy(0, 10000)')
await page.wait_for_timeout(1000) # صبر ثابت برای بارگذاری تصاویر جدید
استفاده توصیهشده: در ترکیب با چکهایی که وجود المانهای تازه را بررسی میکنند.
صبر کردن تا زمانی که شبکه به حالت idle برود با wait_for_load_state('networkidle')؛ اما دقت کنید که بعضی سایتها پس از اسکرول هم ممکن است همچنان درخواستهای طولانیمدت یا polling داشته باشند و حالت networkidle بهتنهایی کافی نباشد.
# مثال: صبر تا networkidle
await page.wait_for_load_state('networkidle', timeout=10000)
بهترین عمل: ترکیب هر دو روش—ابتدا انتظار شبکه، سپس یک تأخیر کوتاه و در نهایت بررسی وجود محتوای جدید (مثلاً تعداد ایتمها تغییر کرده یا یک selector جدید ظاهر شده).
import asyncio
from playwright.async_api import async_playwright
async def click_with_retry(page, selector, retries=3):
delay = 0.5
for i in range(retries):
try:
handle = page.locator(selector)
await handle.wait_for(state='visible', timeout=5000)
await handle.click()
return True
except Exception:
await asyncio.sleep(delay)
delay *= 2
return False
این الگو ورودی: صفحه و selector؛ خروجی: True/False بسته به موفقیت کلیک. مزیت: مقاوم در برابر تاخیرهای موقتی و race conditionها.
اسکرول کردن با Playwright چندین روش دارد و انتخاب درست بستگی به هدف شما، حساسیت سایت به رفتار ربات و نیاز به شبیهسازی کاربر دارد. برای پروژههای وب اسکریپینگ حرفهای:
با درک تفاوت بین این روشها و اعمال بهترینروشهای ذکرشده، میتوانید اسکریپ پایدارتر و قابلاعتمادتر برای اسکریپ کردن صفحات طولانی و سایتهای با لیزیلودینگ ایجاد کنید.


