

در این مقاله قدمبهقدم یاد میگیریم چطور با فریمورک Scrapy یک اسکرپر تولیدی ساده برای یک فروشگاه اینترنتی بسازیم. اهداف آموزشی شامل راهاندازی محیط، ساخت پروژه و اسپایدر، استخراج داده با CSS Selector، پاکسازی سادهی داده، ناوبری بین صفحات (pagination)، و ذخیرهسازی خروجی است. فرض میکنیم خواننده توسعهدهنده پایتون با سطح متوسط است و به جزئیات فنی، توضیحات خطبهخط کد و نکات پایداری/امنیتی نیاز دارد.
Scrapy یک فریمورک کامل پایتون برای اسکریپ کردن صفحات وب است که قابلیتهای همزمانی، مدیریت صف درخواستها، middlewareها، و سیستم pipeline برای پردازش و ذخیرهسازی داده را از ابتدا فراهم میکند. در مقابل ترکیب requests و BeautifulSoup یا ابزارهایی مثل Selenium، Scrapy مقیاسپذیری و امکانات production-ready بیشتری ارائه میدهد، هرچند یادگیری اولیه آن کمی طولانیتر است.
پیش از هر چیز یک virtual environment بسازید تا وابستگیها ایزوله بمانند. در لینوکس/مک:
$ sudo apt-get update
$ sudo apt install -y python3-venv python3-pip
$ cd /path/to/projects
$ python3 -m venv venv
$ source venv/bin/activate
$ pip install --upgrade pip
$ pip install scrapyدر ویندوز:
C:\> pip install virtualenv
C:\> cd \path\to\projects
C:\> virtualenv venv
C:\> venv\Scripts\activate
(venv) C:\> pip install scrapyتوضیح: ورودی این بخش دستورات ترمینال هستند و خروجی انتظار میرود نصب موفق پکیجها و فعالسازی محیط مجازی باشد. در صورت مواجهه با خطاهای کامپايلر یا wheels، پکیجهای موردنیاز سیستمی (مثلاً build-essential یا libxml2-dev) را نصب کنید.
ایجاد پروژه با scrapy startproject <name> یک ساختار پایه میسازد. فایلهای کلیدی:
این تفکیک کمک میکند منطق استخراج از منطق پردازش داده و ذخیرهسازی جدا باقی بماند؛ بهترینروش برای پروژههای پایدار و قابل نگهداری است.
برای تولید یک اسپایدر از دستور scrapy genspider <name> <domain> استفاده کنید. اسپایدر قالبی چیزی شبیه این خواهد داشت:
import scrapy
class ChocolateSpider(scrapy.Spider):
name = 'chocolatespider'
allowed_domains = ['chocolate.co.uk']
start_urls = ['https://www.chocolate.co.uk/collections/all']
def parse(self, response):
passتوضیح: ورودی اولیه این کلاس، درخواست به URLهای موجود در start_urls است. خروجی تابع parse معمولاً آیتمها (به شکل dict یا scrapy.Item) و/یا درخواستهای بعدی (برای pagination یا دنبالکردن لینکها) است.
قبل از نوشتن کد اسپایدر، سلکتورهای CSS/XPath را با scrapy shell تست کنید. نمونه دستورات:
$ scrapy shell
scrapy> fetch('https://www.chocolate.co.uk/collections/all')
scrapy> response # نمایش response
scrapy> response.css('product-item') # گرفتن نودهای محصولمثالهای استخراج در shell (این دستورات در محیط shell اجرا میشوند):
# گرفتن اولین محصول
product = response.css('product-item').get() # یا .get() برای HTML خام
# اگر بخواهیم به عنوان selector کار کنیم:
products = response.css('product-item')
len(products) # تعداد آیتمها
# استخراج نام
products[0].css('a.product-item-meta__title::text').get()
# استخراج URL نسبی
products[0].css('div.product-item-meta a').attrib['href']
# استخراج متن قیمت معمولاً بهتر با ::text یا join کردن تمام متن داخلی
''.join(products[0].css('span.price ::text').getall()).strip()نکته: ترجیح دهید از ::text یا getall() و سپس پاکسازی متن استفاده کنید تا از دستکاری HTML خام با replace اجتناب شود.
import scrapy
class ChocolateSpider(scrapy.Spider):
name = 'chocolatespider'
start_urls = ['https://www.chocolate.co.uk/collections/all']
def parse(self, response):
products = response.css('product-item')
for p in products:
name = p.css('a.product-item-meta__title::text').get()
# جمعآوری تمام قطعات متن قیمت و پاکسازی
raw_price_parts = p.css('span.price ::text').getall()
price = ''.join(raw_price_parts).replace('Sale price', '').strip()
url = p.css('div.product-item-meta a').attrib.get('href')
yield {
'name': name.strip() if name else None,
'price': price,
'url': response.urljoin(url) if url else None,
}
# pagination: اگر صفحه بعدی وجود دارد، از response.follow استفاده کنید
next_page = response.css('[rel="next"] ::attr(href)').get()
if next_page:
yield response.follow(next_page, callback=self.parse)توضیح کد (ورودی/خروجی و نقش هر بخش):
برای اجرای اسپایدر و ذخیره خروجی در JSON یا CSV از گزینه -O استفاده کنید:
$ scrapy crawl chocolatespider -O products.json
# یا
$ scrapy crawl chocolatespider -O products.csvتوضیح: این دستور اسپایدر را اجرا میکند، آیتمهای yield شده را به فایل تعیینشده میریزد و آمار run را در لاگ نمایش میدهد.
برای پروژههای بزرگتر بهتر است ساختار آیتمها را در items.py تعریف کنید و پردازش پاکسازی و اعتبارسنجی را در Item Pipeline منتقل کنید. مثال ساده:
# items.py
import scrapy
class ProductItem(scrapy.Item):
name = scrapy.Field()
price = scrapy.Field()
url = scrapy.Field()
# در pipelines.py میتوانید قیمت را به عدد تبدیل کنید، فیلترهای duplicate بزنید یا ذخیره در دیتابیس انجام دهید.مزیت: جدا کردن وظایف، تستپذیری بهتر و قابلیت استفاده در چند اسپایدر.
مواردی که در تولید باید رعایت شود:
نمونه تنظیمات پایه برای محدودسازی سرعت (در settings.py):
# settings.py
DOWNLOAD_DELAY = 1 # یک ثانیه بین درخواستها
CONCURRENT_REQUESTS = 8
RETRY_TIMES = 3
USER_AGENT = 'my-scraper/1.0 (+contact@example.com)'
ROBOTSTXT_OBEY = Trueدر این راهنما با مراحل عملی ساخت یک اسکرپر پایه در Scrapy آشنا شدید: از راهاندازی محیط، تست سلکتورها با Scrapy Shell، نوشتن اسپایدر، پاکسازی دادهها، تا پیمایش صفحات و ذخیرهسازی خروجی. برای آمادهسازی اسپایدر برای محیط تولید، به تنظیمات concurrency، مدیریت retries، استفاده از pipelines، و برنامهریزی اجرا (scheduling) نیاز دارید. قدم بعدی میتواند کار روی Item Pipelines برای پاکسازی بهتر، ذخیرهسازی در دیتابیس، و افزودن middleware برای پراکسی و چرخش user-agent باشد.


