

در اسکریپینگ، فشار زیاد به سرور هدف از طریق ارسال پیدرپی درخواستها میتواند تجربه کاربران واقعی را خراب کند و حتی شبیه یک حمله DDoS شود. در این مقاله عملی مخصوص توسعهدهندگان پایتون، روشهای معتبر و مؤثر برای قرار دادن تأخیر بین درخواستها در Scrapy را توضیح میدهیم. در پایان میآموزید چگونه از DOWNLOAD_DELAY، تأخیرهای تصادفی یا ثابت و افزونه AutoThrottle استفاده کنید و بهترین تنظیمهای عملکرد و پایداری را برقرار کنید.
در اسکریپرهای ساده مبتنی بر requests معمولاً توسعهدهندگان از time.sleep برای تأخیر بین درخواستها استفاده میکنند. اما در Scrapy این کار اشتباه است، چون Scrapy از فریمورک همزمانی Twisted استفاده میکند و فراخوانی time.sleep واکنشگر (reactor) را مسدود میکند. نتیجهٔ این کار توقف کامل کانکرنسی، صفبندی نامناسب درخواستها و کاهش شدید کارایی است.
به جای آن باید از تنظیمات داخلی Scrapy یا افزونههای غیرمسدودکننده استفاده کنید تا همزمانی حفظ شود و تأخیرها بهصورت غیربلوککننده اعمال شوند.
سادهترین روش گذاشتن تأخیر بین درخواستها، تنظیم DOWNLOAD_DELAY در settings.py است. مقدار پیشفرض 0 است که یعنی هیچ تأخیری وجود ندارد؛ با انتخاب مقدار غیرصفر، Scrapy بین درخواستهای ارسالشده به همان دامنه تاخیر اعمال میکند.
# settings.py
DOWNLOAD_DELAY = 2 # 2 ثانیه تأخیر حداقل برای هر دامنههمچنین میتوانید این مقدار را بهصورت محلی برای هر اسپایدر با custom_settings تعیین کنید (مفید وقتی اسپایدرها را با CrawlerProcess اجرا میکنید):
# bookspider.py
import scrapy
class BookSpider(scrapy.Spider):
name = 'bookspider'
start_urls = ['http://books.toscrape.com']
custom_settings = {
'DOWNLOAD_DELAY': 2, # 2 ثانیه
}
def parse(self, response):
# ورودی: response از یک صفحه
# خروجی: آیتمهایی که yield میشوند یا درخواستهای بعدی
for article in response.css('article.product_pod'):
yield {
'url': article.css('h3 > a::attr(href)').get(),
'title': article.css('h3 > a::attr(title)').get(),
'price': article.css('.price_color::text').get(),
}توضیح کوتاه: این اسپایدر با هر پاسخ یک مجموعه آیتم میسازد و شکل کارکرد DOWNLOAD_DELAY تضمین میکند که بین درخواستها برای همان دامنه فاصلهای حداقل وجود داشته باشد.
بهصورت پیشفرض، Scrapy وقتی DOWNLOAD_DELAY تعیین کرده باشید، مقدار واقعی تأخیر را کمی تصادفی میکند تا الگوی ثابت نشود. این خصلت با تنظیم پیشفرض RANDOMIZE_DOWNLOAD_DELAY = True فعال است و محدودهٔ تأخیر بین 0.5 * DOWNLOAD_DELAY تا 1.5 * DOWNLOAD_DELAY خواهد بود. برای مثال با DOWNLOAD_DELAY = 2 تأخیر واقعی بین حدود 1 تا 3 ثانیه قرار میگیرد.
مزیت: تقلید رفتار انسانی بهتر و کاهش شناسایی توسط سیستمهای دفاعی. معایب: بازده کلی پایینتر و نوسان زمان اجرا.
اگر خواستید تأخیر دقیق و ثابتی بین درخواستها اعمال شود، RANDOMIZE_DOWNLOAD_DELAY را به False تنظیم کنید:
# settings.py
DOWNLOAD_DELAY = 2
RANDOMIZE_DOWNLOAD_DELAY = False # تأخیر دقیق 2 ثانیه بین درخواستهانکته: تأخیر ثابت باعث میشود رفتار شما قابلپیشبینیتر شود که ممکن است برخی سیستمها را برای شناسایی آسانتر کند؛ معمولاً ترکیب محدودهٔ تصادفی با مقادیر مناسب بهتر است.
AutoThrottle افزونهای داخلی در Scrapy است که بهصورت پویا تأخیرها را بر اساس تأخیر پاسخها (latency) و وضعیت پاسخها تنظیم میکند. مزیت بزرگ آن این است که خودش سعی میکند بار روی سرور هدف را کاهش دهد و در مواجهه با خطاها یا تأخیرهای زیاد کندتر عمل کند.
برای فعالسازی کافیست در settings.py یا custom_settings آن را روشن کنید:
# settings.py
DOWNLOAD_DELAY = 2 # حداقل تأخیر
AUTOTHROTTLE_ENABLED = True
AUTOTHROTTLE_START_DELAY = 5.0
AUTOTHROTTLE_MAX_DELAY = 60.0
AUTOTHROTTLE_TARGET_CONCURRENCY = 1.0
AUTOTHROTTLE_DEBUG = False # True برای نمایش آمار در زمان اجراشرح پارامترها:
# settings.py (پیشنهاد برای اسکریپینگ مودبانه)
DOWNLOAD_DELAY = 1.5
RANDOMIZE_DOWNLOAD_DELAY = True
AUTOTHROTTLE_ENABLED = True
AUTOTHROTTLE_START_DELAY = 2.0
AUTOTHROTTLE_MAX_DELAY = 30.0
AUTOTHROTTLE_TARGET_CONCURRENCY = 1.0
CONCURRENT_REQUESTS = 16
CONCURRENT_REQUESTS_PER_DOMAIN = 4
CONCURRENT_REQUESTS_PER_IP = 4
# رعایت robots.txt را نیز در نظر بگیرید
ROBOTSTXT_OBEY = True
# زمانبندی retry و middlewareها را متناسب با نیاز تنظیم کنیدتوضیح کلی:
بهجای استفاده از time.sleep، از امکانات خود Scrapy بهره ببرید: DOWNLOAD_DELAY و RANDOMIZE_DOWNLOAD_DELAY کنترل سادهای فراهم میکنند و AutoThrottle بهترین گزینه برای تطبیق خودکار با شرایط سرور است. تنظیم درست همزمانی، رندومسازی و مانیتورینگ باعث میشود اسکریپهای شما هم مؤثر و هم مؤدب باشند.


