مقدمه
این مقاله برای توسعهدهندههای پایتون در سطح متوسط نوشته شده که میخواهند بفهمند چه زمانی باید از Selenium (مرورگر خودکار) استفاده کنند و چه زمانی کافی است از Requests (کلاینت HTTP) بهره ببرند. در پایان این مطلب شما یاد میگیرید تفاوتهای عملکردی، موارد استفاده مناسب، نقاط ضعف هر روش و چگونه میتوان آنها را ترکیب کرد تا هم قابلاعتماد و هم سریع اسکِرِپ کنید.
معرفی سریع: Selenium چیست؟
Selenium یک کتابخانهٔ اتوماسیون مرورگر است که صفحات را در یک موتور مرورگر واقعی رندر میکند و اجازهٔ تعامل (کلیک، اسکرول، پر کردن فرم، گرفتن اسکرینشات و...) را میدهد. این گزینه زمانی مناسب است که محتوای صفحه با جاوااسکریپت تولید میشود یا نیاز به تعامل کاربر مانند لاگین و پیمایش دینامیک دارید.
- کاربردها: رندر صفحات SPA، لاگین اتوماتیک، گرفتن اسکرینشات، شبیهسازی رفتار واقعی کاربر.
- معایب: مصرف حافظه و پهنایباند بالاتر، هزینهٔ پروکسی و کندی نسبت به درخواستهای مستقیم HTTP.
مثال سادهٔ Selenium برای استخراج تگ <h1> از یک صفحه:
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
# Set up headless Chrome
opts = Options()
opts.headless = True
chrome = webdriver.Chrome(options=opts)
url = 'http://quotes.toscrape.com/page/1/'
chrome.get(url) # ورودی: url --> خروجی: صفحهٔ رندر شده در مرورگر
# منتظر یک عنصر باشیم تا از بارگذاری JS مطمئن شویم
h1_elem = WebDriverWait(chrome, 10).until(
EC.presence_of_element_located((By.TAG_NAME, 'h1'))
)
h1_text = h1_elem.text # خروجی نهایی: متن داخل تگ h1
print(h1_text)
chrome.quit()
توضیح کوتاه کد: در این مثال ورودی تابع اصلی url است، webdriver.Chrome یک مرورگر (headless) باز میکند، get صفحه را بارگذاری میکند، سپس با WebDriverWait تا حضور تگ h1 منتظر میماند و متن آن را میخواند.
معرفی سریع: Requests چیست؟
Requests یک کتابخانهٔ ساده و قدرتمند برای ارسال درخواستهای HTTP است. این روش مناسب زمانی است که محتوا بهصورت HTML یا JSON از سرور برمیگردد و نیازی به رندر جاوااسکریپت یا تعامل پیچیده نیست.
- کاربردها: اسکریپینگ در مقیاس بزرگ، دسترسی به APIها، کاهش هزینهها و افزایش سرعت.
- معایب: نمیتواند صفحهٔ سمت کاربر را رندر کند و تعامل با عناصر صفحه نیاز به مهندسی معکوس APIها دارد.
مثال Requests به همراه BeautifulSoup برای استخراج همان تگ <h1>:
import requests
from bs4 import BeautifulSoup
url = 'http://quotes.toscrape.com/page/1/'
resp = requests.get(url, timeout=10) # ورودی: url؛ خروجی: شیٔ response حاوی متن HTML
soup = BeautifulSoup(resp.text, 'html.parser')
h1_text = soup.find('h1').get_text()
print(h1_text)
توضیح: requests.get صفحهٔ خام را برمیگرداند؛ سپس با BeautifulSoup آن را پارس میکنیم تا اطلاعات مورد نظر را استخراج کنیم.
وقتی باید از Selenium استفاده کنید
- صفحات دینامیک (JS-heavy): وقتی دادهها فقط بعد از اجرای جاوااسکریپت ظاهر میشوند.
- تعامل زیاد با صفحه: کلیکهای متوالی، فرمهای پیچیده، المانهای بازشونده و اسکرول بینهایت.
- اسکرینشات یا ریپلِی رفتار کاربر: نیاز به گرفتن تصویر از صفحه یا ویدیو از مراحل وجود دارد.
- اسکریپتهای محافظتی یا سیستمهای ضدبات قوی: در برخی موارد اجرای یک مرورگر واقعی شانس عبور از تشخیص را افزایش میدهد.
نکتهٔ عملی: برای پایداری بهتر از WebDriverWait و سلکتورهای مقاوم استفاده کنید و از بارگذاری دوبارهٔ مرورگر برای هر صفحه خودداری کنید (اگر مقیاس کوچک است). همچنین قابلیت headless را با احتیاط استفاده کنید چون بعضی از سایتها headless بودن را تشخیص میدهند.
وقتی باید از Requests استفاده کنید
- اسکریپینگ در مقیاس بالا: مصرف منابع و پهنایباند پایینتر و سرعت بیشتر.
- دسترسی به APIها: وقتی دادهها از طریق endpointهای JSON در دسترس است.
- کاهش هزینهها: مصرف کمتر منابع سرور و پروکسی.
- نیاز به سرعت بالا: وقتی هر میلیثانیه اهمیت دارد از sessionها و کانکشنهای پایدار استفاده کنید.
مثال بهینهسازی با Session و retry برای Requests:
import requests
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry
session = requests.Session()
retries = Retry(total=5, backoff_factor=0.5, status_forcelist=[500, 502, 503, 504])
session.mount('https://', HTTPAdapter(max_retries=retries))
resp = session.get('https://example.com', timeout=10) # ورودی: URL؛ خروجی: response
print(resp.status_code)
توضیح: استفاده از Session اتصالات را بازنگه میدارد و تاخیر را کاهش میدهد. Retry برای تحمل خطاهای موقتی و timeout برای جلوگیری از بلوکهشدن ناخواسته مهم است.
ترکیب Selenium و Requests (روش عملی متداول)
ترکیب دو روش رایج است: از Selenium برای لاگین یا رندر اولیه استفاده میکنیم، سپس کوکیها یا توکن را به یک جلسهٔ Requests منتقل میکنیم تا ادامهٔ اسکریپینگ سریعتر و کمهزینهتر باشد.
# گام 1: با Selenium لاگین کن و کوکیها را بگیر
from selenium import webdriver
from requests import Session
driver = webdriver.Chrome()
driver.get('https://example.com/login')
# (کد ورود خودکار: پر کردن فرم و submit)
cookies = driver.get_cookies() # خروجی: لیست کوکیها
session = Session()
for c in cookies:
session.cookies.set(c['name'], c['value'], domain=c.get('domain'))
# گام 2: با requests session ادامهٔ اسکریپینگ را انجام بده
resp = session.get('https://example.com/protected-page')
print(resp.status_code)
driver.quit()
توضیح: این الگو ورودیاش صفحهٔ ورود است، خروجی دریافت کوکی و سپس استفاده از همان جلسهٔ HTTP برای درخواستهای بعدی است؛ مزیت: سرعت و کاهش مصرف منابع نسبت به نگهداشتن مرورگر برای همیشه.
نکات عملی، امنیت و بهینگی
- Timeout و Retry: همیشه timeout تنظیم کنید و از مکانیزم retry با backoff استفاده کنید تا از بلوکه شدن یا hanging جلوگیری کنید.
- تنظیم هدرها و User-Agent: با تعویض User-Agent و هدرها احتمال شناسایی کاهش مییابد اما به تنهایی کافی نیست.
- ریسپکت به قوانین: قبل از اسکریپینگ robots.txt و قوانین سایت را بررسی کنید و از بارگذاری بیش از حد جلوگیری کنید.
- پروکسیها و هزینهها: اگر پروکسی بر اساس GB یا درخواست محاسبه میشود، Selenium میتواند بسیار پرهزینه باشد. از پروکسیهای روتیتشونده و محدودیت نرخ استفاده کنید.
- پایداری و مانیتورینگ: لاگگیری، متریک مصرف حافظه و دیدهبانی خطاها برای اسکریپرهای تولیدی ضروری است.
- امنیت و حریم خصوصی: نگهداری و انتقال کوکیها و توکنها را امن انجام دهید و اطلاعات حساس را رمزنگاری کنید.
جمعبندی
نکتهٔ کلیدی این است که هیچیک از ابزارها «بهطور مطلق» بر دیگری برتری ندارد؛ انتخاب بین Selenium و Requests بستگی به نیازمندیهای پروژه (تعامل با صفحه، مقیاس، هزینه و پایداری) دارد. برای بیشتر پروژهها ترکیب هوشمندانهٔ هر دو—Selenium برای جاهایی که نیاز به رندر یا لاگین است و Requests برای استخراج سریع و حجم بالا—بهترین نتیجه را میدهد. در نهایت از استراتژیهای retry، timeout، مانیتورینگ و رعایت قوانین سایت غافل نشوید.





