مقدمه
هدف وب اسکریپینگ تبدیل HTMLِ نامنظم به دادههای ساختیافتهای است که بتوان در اپلیکیشنها یا پایپلاینهای دادهای از آنها استفاده کرد. بسیاری از توسعهدهندگان در شروع کار خروجی خود را به شکل دیکشنری برمیگردانند، اما Scrapy یک روش ساختیافتهتر و امنتر به نام Items ارائه میدهد که نگهداری، اعتبارسنجی و پردازش دادهها را آسانتر میکند.
در پایان این راهنما شما یاد میگیرید چطور Item را تعریف کنید، آن را در اسپایدر به کار ببرید، ارتباطش را با پایپلاینها برقرار کنید و بهترینروشها و نکات مربوط به عملکرد و امنیت را رعایت کنید.
چیستند Scrapy Items و چرا استفاده کنیم
Items در Scrapy یک ساختار داده از پیش تعریفشده هستند که فیلدهای مورد انتظار را مشخص میکنند. برخلاف دیکشنری ساده، Item یک اسکیمای مشخص فراهم میکند و در ترکیب با ابزارهای Scrapy مثل Item Loaders و Item Pipelines، امکان پاکسازی، اعتبارسنجی، dedup، و خروجیگیری منظم را میدهد.
- ساختاردهی واضح به دادهها و کاهش خطاهای تایپی در کلیدها.
- امکان اجرای اعتبارسنجی و پاکسازی متمرکز در پایپلاینها.
- سهولت در اکسپورت منظم با سیستم Feed Exports.
- قابلیت همکاری بهتر با Item Loaders و تستهای واحد.
Scrapy همچنین از انواع دیگری مثل دیکشنریها، dataclass و attrs پشتیبانی میکند، اما تعریف یک کلاس Item در items.py معمولاً خواناتر و قابل نگهداریتر است.
تعریف یک Item
برای تعریف Item کافی است در فایل items.py از کلاس پایه Item ارث ببرید و فیلدها را با Field مشخص کنید. مثال زیر یک Item ساده برای نقلقولها را نشان میدهد:
from scrapy.item import Item, Field
class QuoteItem(Item):
text = Field()
tags = Field()
author = Field()
توضیح مختصر:
- ورودی: تعریف ثابت کد در فایل پروژه (items.py).
- خروجی: ساختار کلاسمانند که هنگام yield شدن، شیءای از آن ساخته و بهعنوان دادهٔ پروژه منتقل میشود.
- نقش: مستندسازی فیلدهای مورد انتظار و فراهمکردن پایهای برای پاکسازی/اعتبارسنجی.
ادغام Item در اسپایدر
در اسپایدر بهجای برگرداندن دیکشنری، یک نمونه جدید از Item بسازید و فیلدها را پر کنید. نکتهٔ مهم این است که هر بار یک نمونه جدید داخل حلقه بسازید تا از اشتراکگذاری نمونه و بروز دادههای نادرست جلوگیری شود.
import scrapy
from items_demo.items import QuoteItem
class QuotesSpider(scrapy.Spider):
name = 'quotes'
def start_requests(self):
url = 'https://quotes.toscrape.com/'
yield scrapy.Request(url, callback=self.parse)
def parse(self, response):
for quote_sel in response.css('div.quote'):
quote_item = QuoteItem() # هر بار یک نمونه جدید
quote_item['text'] = quote_sel.css('span.text::text').get()
quote_item['author'] = quote_sel.css('small.author::text').get()
quote_item['tags'] = quote_sel.css('div.tags a.tag::text').getall()
yield quote_item
خطبهخط:
- در start_requests درخواست اولیه ساخته میشود و به متد parse ارسال میگردد.
- برای هر بلاک HTML مربوط به یک نقلقول، یک QuoteItem جدید ساخته میشود.
- با استفاده از سلکتورهای CSS، مقدار هر فیلد استخراج و در Item قرار میگیرد.
- در نهایت Item توسط Scrapy دریافت و به صف پایپلاینها فرستاده میشود.
نکتهٔ عملی: اگر نیاز به پاکسازی یا نرمالسازی دارید، از ItemLoader استفاده کنید تا قوانین پاکسازی را به شکل متمرکز و قابل تست تعریف کنید.
نمونه ItemLoader (کوتاه)
from scrapy.loader import ItemLoader
from items_demo.items import QuoteItem
loader = ItemLoader(item=QuoteItem(), selector=quote_sel)
loader.add_css('text', 'span.text::text')
loader.add_css('author', 'small.author::text')
loader.add_css('tags', 'div.tags a.tag::text')
quote_item = loader.load_item()
ItemLoader این امکان را میدهد که تبدیلها و پردازشهای پیشفرض را روی فیلدها اعمال کنید (مثلاً strip، join و غیره) بدون پاکشدن منطق اسپایدر.
پایپلاینها، Feed Exports و اعتبارسنجی
پس از yield شدن Item، آنرا میتوان با پایپلاینها پردازش، اعتبارسنجی و ذخیره کرد. مثال زیر یک پایپلاین ساده اعتبارسنجی و حذف آیتمهای ناقص را نشان میدهد:
from scrapy.exceptions import DropItem
class ValidatePipeline:
def process_item(self, item, spider):
if not item.get('text'):
raise DropItem('missing text')
# مثال پاکسازی ساده
item['author'] = item.get('author', '').strip()
return item
نکات مهم:
- برای dedup میتوان از یک پایپلاین مبتنی بر شناسهٔ یکتا (مثلاً هش متن یا ترکیب فیلدها) استفاده کرد.
- Feed Exports داخلی Scrapy خروجیها را به JSON/CSV/… تبدیل میکند؛ Items باعث میشوند خروجیها منظم و قابل پیشبینی باشند.
- اعتبارسنجی و پاکسازی هزینه محاسباتی دارد — در اسکریپینگ پرسرعت این هزینه را در طراحی مدنظر قرار دهید.
نکات امنیتی، عملکرد و مدیریت خطا
- هرگز محتوای HTML یا جاوااسکریپت استخراجشده را بدون پاکسازی اجرا نکنید. دادهها را فقط بهعنوان متن/فیلد ذخیره کنید و در صورت نیاز برای نمایش، ایمنسازی (escape/sanitize) کنید.
- اعتبارسنجی سنگین میتواند عملکرد را کاهش دهد؛ برای اسکریپهای دربازهٔ بالا میتوانید از پردازش دستهای یا صفبندی برای پردازش پسزمینه استفاده کنید.
- برای مدیریت خطا در متد parse از ساختارهای try/except استفاده کنید و در صورت نیاز آیتم را با یک فیلد وضعیتِ خطا برگردانید یا آن را Drop کنید.
- همزمانی (concurrency) و تعداد درخواستها را طوری تنظیم کنید که سایت هدف را تحت فشار نگذارید و با IP ban یا throttling مواجه نشوید.
بهترین شیوهها
- فیلدها را صریح و مستندسازیشده تعریف کنید تا تیم روی یک اسکیمای واحد کار کند.
- در اسپایدر، هر بار نمونهٔ جدید بسازید و از اشتراکگذاری جلوگیری کنید.
- برای پاکسازی و نرمالسازی از ItemLoader و برای اعتبارسنجی از پایپلاینها استفاده کنید.
- برای پروژههای بزرگتر، تست واحد برای Itemها و پایپلاینها بنویسید تا از رفتار صحیح اطمینان حاصل شود.
- در صورت نیاز به حداکثر سرعت، پروفایلینگ انجام دهید؛ گاهی استفادهٔ دیکشنری در مرحلهٔ جمعآوری و تبدیل نهایی به Item میتواند بازده بالاتری بدهد، اما قابلیت اطمینان و خوانایی را کاهش میدهد.
جمعبندی
استفاده از Items در Scrapy یک شیوهٔ ساده اما قدرتمند برای ساختاردهی، پاکسازی و اعتبارسنجی دادههای استخراجشده است. با ترکیب Items، ItemLoader و Item Pipelines میتوانید یک جریان دادهای قابلاعتماد و تستپذیر بسازید که بهراحتی قابل نگهداری و مقیاسپذیر است. در پروژههای حساس به عملکرد، تعادل میان اعتبارسنجی در لحظه و پردازش پسزمینه را در نظر بگیرید.





