مقدمه
در این راهنما مقایسهای عملی بین دو روش مرسوم در اسکریپینگ با پایتون ارائه میکنیم: Selenium (شبیهسازی مرورگر، مناسب برای صفحات دینامیک) و Scrapy (چارچوب خزندهٔ مقیاسپذیر، مناسب برای خزش عظیم). فرض میکنیم مخاطب توسعهدهندهٔ پایتون در سطح متوسط است؛ در پایان این مطلب شما خواهید دانست چه زمانی هر ابزار مناسب است، چطور آنها را نصب و راهاندازی کنید، نمونههای کد گامبهگام و بهترین روشها برای عملکرد، پایداری و امنیت.
خلاصهٔ کاربردها و تصمیمگیری سریع
- Selenium: وقتی صفحه به جاوااسکریپت وابسته است، باید با کلیک، اسکرول یا تکمیل فرم تعامل کنید، یا نیاز به عکس/رندر کامل صفحه دارید.
- Scrapy: وقتی حجم صفحات زیاد است، نیاز به خزش موازی و پردازش ساختاریافته دارید و محتوای هدف عمدتاً به صورت استاتیک در خروجی HTML موجود است.
Selenium - چه چیزی، چه زمانی و چرا
Selenium یک کتابخانهٔ اتوماسیون مرورگر است که رفتار کاربر را شبیهسازی میکند: باز کردن صفحه، کلیک، ارسال کلید و گرفتن اسکرینشات. برای صفحات دینامیک و عملیات نیازمند تعامل (مثل لاگین با فرمهای جاوااسکریپتی، باز کردن مودالها و رندر شدن محتوای client-side) عالی است، اما هزینهٔ منابع بالاتری دارد.
مزایا و معایب را خلاصه میکنیم:
- مزایا: شبیهسازی کاربر واقعی، پشتیبانی کامل از جاوااسکریپت، توانایی گرفتن اسکرینشات و مدیریت پنجرهها/پاپآپها.
- معایب: مصرف زیاد حافظه و CPU، وابستگی به درایور مرورگر (مثلاً chromedriver)، کندی نسبت به خزندههای غیرمرورگری در مقیاس بزرگ.
نمونهٔ پایه با Selenium
کد زیر یک نمونهٔ ساده است که صفحهای را باز میکند، لینکها را اسکن میکند و روی لینک «Login» کلیک میکند. ورودی: آدرس صفحه؛ خروجی: تعامل با صفحه (ناوبری) و امکان ذخیرهٔ page_source.
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
# ایجاد نمونهٔ کروم (در عمل از options برای headless و بهینهسازی استفاده کنید)
driver = webdriver.Chrome()
a_url = "https://quotes.toscrape.com"
driver.get(a_url)
# گرفتن همه لینکها و کلیک روی لینک Login
links = driver.find_elements(By.TAG_NAME, "a")
target = None
for link in links:
if link.text.strip() == "Login":
target = link
break
if target:
target.click()
# منتظر بمان تا عنصر مشخصی ظاهر شود (مثال: یک فیلد نام کاربری)
WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.NAME, "username"))
)
# اکنون میتوانید send_keys یا سایر تعاملات را انجام دهید
# ذخیرهٔ HTML فعلی
with open("selenium_page.html", "w", encoding="utf-8") as f:
f.write(driver.page_source)
driver.quit()توضیح خطبهخط (خلاصه):
- ایمپورت ماژولها: راهاندازی درایور و ابزارهای انتظار (WebDriverWait, EC).
- driver.get: ورودی URL را میگیرد و صفحه را لود میکند.
- find_elements: لیستی از عناصر بازمیگرداند؛ سپس با حلقه دنبال عنصرِ موردنظر میگردیم.
- با click() تعامل انجام میشود و WebDriverWait تضمین میکند که تا زمانی که عنصر موردنظر آماده نشود، ادامه نمیدهد.
- خروجی نمونه: فایل HTML محلی و/یا وضعیت صفحه پس از تعامل؛ منابع مرورگر آزاد میشوند با quit().
نکات عملی و بهینهسازی:
- برای اجرای سرور/محیط CI از حالت headless و گزینههای غیرفعالکنندهٔ بارگزاری تصاویر و فونتها استفاده کنید تا مصرف کاهش یابد.
- همیشه نسخهٔ درایور را با نسخهٔ مرورگرتان همخوان کنید.
- کلیدهای امنیتی (مثل API_KEYها) را در متغیرهای محیطی نگهداری کنید، نه داخل کد.
Scrapy - اصول و نمونهٔ کاربردی
Scrapy یک فریمورک کامل برای خزش و استخراج داده است که بهصورت ناهمزمان و بهینه طراحی شده است. برای استخراج ساختاریافتهٔ حجم زیاد صفحات، اجرای زمانبندی شده و pipelineهای پردازشی بسیار مناسب است.
مزایا: اجرای موازی، مصرف کمتر در مقایسه با باز کردن مرورگر برای هر صفحه، قابلیت تعریف pipelines و middlewares، و یک ساختار پروژهٔ آماده.
نمونهٔ سادهٔ Spider در Scrapy
این اسپایدر مجموعهای از صفحات را درخواست میکند و HTML هر صفحه را بهصورت باینری ذخیره مینماید. ورودی: لیست URLها؛ خروجی: فایلهای HTML محلی و لاگِ ذخیرهشدن.
from pathlib import Path
import scrapy
class QuotesSpider(scrapy.Spider):
name = "quotes"
def start_requests(self):
urls = [
"https://quotes.toscrape.com/page/1/",
"https://quotes.toscrape.com/page/2/",
"https://quotes.toscrape.com/page/3/",
]
for url in urls:
yield scrapy.Request(url=url, callback=self.parse)
def parse(self, response):
# گرفتن شماره صفحه از URL
page = response.url.split("/")[-2]
filename = f"quotes-{page}.html"
Path(filename).write_bytes(response.body)
self.log(f"saved file: {filename}")توضیح عملکرد:
- start_requests: تولید کنندهٔ درخواستها (inputs: لیست URLها). Scrapy آنها را به صورت ناهمزمان اجرا میکند.
- parse: callback که پاسخ (response) را دریافت میکند. response.body بایتهای HTML را نگهداری میکند؛ ما آنها را در فایل ذخیره میکنیم.
- خروجی: فایلهای HTML و پیامهای لاگ.
پراکسی، دور زدن بلاکها و مثال کمکی
وبسایتهای بزرگ معمولاً مکانیزمهای ضداسکریپینگ دارند؛ استفاده از پراکسی، چرخش User-Agent و مدیریت نرخ درخواستها ضروری است. در مثالهای منبع از تابعی برای مسیریابی از طریق پراکسی استفاده شده است — نمونهٔ امن و سادهٔ آن:
from urllib.parse import urlencode
API_KEY = "YOUR_SCRAPEOPS_API_KEY"
def get_scrapeops_url(url: str) -> str:
payload = {
"api_key": API_KEY,
"url": url,
}
proxy_url = "https://proxy.scrapeops.io/v1/?" + urlencode(payload)
return proxy_urlنقش و ورودی/خروجی:
- ورودی: url (رشته)، API_KEY از متغیر محیطی بهتر است.
- خروجی: آدرسی که باید به عنوان مقصد در driver.get یا scrapy.Request استفاده شود تا ترافیک از طریق پراکسی عبور کند.
نکتهٔ مهم: هرگز کلیدهای واقعی را در مخزن کد منتشر نکنید؛ از متغیرهای محیطی یا secret manager استفاده کنید.
مقایسهٔ فنی و شرایط تصمیمگیری
چند نکتهٔ کلیدی برای انتخاب ابزار:
- اگر هدف شما صفحات استاتیک یا لینکمحور با حجم بالا است: Scrapy را انتخاب کنید (موازی، سریع، قابل توسعه).
- اگر باید رندر کامل صفحه به همراه تعاملات کاربری را شبیهسازی کنید: Selenium مناسبتر است.
- برای سایتهای محافظتشده: ترکیب پراکسی، چرخش User-Agent، و throttling ضروری است؛ Scrapy معمولاً با middlewareها سادهتر عمل میکند.
بهینهسازی، خطایابی و بهترین روشها
توصیههای عملی برای پایداری و عملکرد:
- در Scrapy از AUTOTHROTTLE و تنظیم CONCURRENT_REQUESTS استفاده کنید تا نرخ و بار سرور هدف را مدیریت کنید.
- برای Selenium: استفاده از حالت headless، غیرفعال کردن بارگزاری تصاویر و تعیین timeout معقول کمک میکند.
- همیشه مکانیزم retry و مدیریت استثنا داشته باشید—چه در سطح درخواست (Scrapy) و چه در سطح تعاملات مرورگر (Selenium).
- رعایت قوانین اخلاقی: قبل از اسکریپ کردن robots.txt را بررسی کنید و دادههای حساس یا شخصی را بدون اجازه استخراج نکنید.
- برای CAPTCHA یا ابزارهای پیچیدهٔ ضدربات از سرویسهای معتبر یا تکنیکهایی مثل سرویس تشخیص تصویر و تعامل انسانی برنامهریزیشده استفاده کنید (و در چارچوب قانون عمل کنید).
ترکیب Scrapy و Selenium
در عمل، بسیاری از پروژهها از ترکیب دو ابزار بهره میبرند: از Scrapy برای خزش و مدیریت موازی و از Selenium برای رندر صفحات خاص یا تعاملات نیازمند JS. دو رویکرد معمول:
- استفاده از middleware در Scrapy که در صورت نیاز یک درخواست را به Selenium پاس میدهد و HTML رندرشده را برمیگرداند.
- اجرای Selenium مستقل برای صفحات خاص و سپس ارسال HTMLهای رندرشده به pipelineهای Scrapy برای پردازش و ذخیرهسازی.
نکات فنی هنگام ترکیب:
- به خاطر داشته باشید Selenium کند است؛ فقط برای صفحات ضروری از آن استفاده کنید.
- مکانیزم cache و ذخیرهٔ نتایج رندرشده را پیاده کنید تا از بازوبند شدن مجدد جلوگیری کنید.
جمعبندی و توصیههای نهایی
برای انتخاب درست: اگر پروژهٔ شما شامل خزش بزرگ و استخراج ساختاریافته است، از Scrapy استفاده کنید. اگر تعامل کاربری یا رندر کامل صفحه لازم است، Selenium مناسبتر است. در بسیاری از پروژههای واقعی، ترکیب هوشمندانهٔ هر دو بهترین تعادل بین سرعت و قابلیت را میدهد. همیشه از پراکسی و چرخش هدرها استفاده کنید، کلیدها را امن نگه دارید، و قوانین سایتها و حریم خصوصی را رعایت کنید.





