خانه/مقالات/ذخیره JSON در Scrapy: راهنمای عملی اسکریپینگ
برنامه نویسی
استخراج داده
برگشت به مقاله‌ها

ذخیره JSON در Scrapy: راهنمای عملی اسکریپینگ

ذخیره JSON در Scrapy: راهنمای عملی اسکریپینگ
این مقاله روش‌های عملی ذخیره‌سازی خروجی‌های Scrapy را برای توسعه‌دهندگان پایتون توضیح می‌دهد؛ از تفاوت JSON و JSON Lines تا پیکربندی <strong>FEEDS</strong>، نام‌گذاری داینامیک، بچ‌بندی فایل‌ها و نکات عملکردی و امنیتی.
آسان اسکریپ آسان اسکریپ
1405-04-12

مقدمه

در این راهنما نکات عملی ذخیره‌سازی خروجی‌های وب اسکریپینگ با Scrapy را مرور می‌کنیم. فرض می‌کنیم برنامه‌نویس پایتون در سطح متوسط هستید؛ در پایان خواهید توانست نتایج اسکریپ کردن را به JSON یا JSON Lines صادر کنید، تنظیمات FEEDS را پیکربندی کنید، فایل‌ها را به صورت بچ‌بندی ذخیره کنید و مشکلات رایج عملکرد و امنیت را حل کنید.

Feed Exporters چیست؟

Scrapy یک مجموعه آماده به‌نام Feed Exporters دارد که روش‌های متنوعی برای نوشتن آیتم‌های استخراج‌شده به فرمت‌ها و مقاصد مختلف فراهم می‌کند.

فرمت‌های رایج خروجی:

  • JSON و JSON Lines
  • CSV
  • XML
  • pickle

مقاصد ذخیره‌سازی:

  • فایل محلی
  • FTP
  • Amazon S3
  • Google Cloud Storage
  • STDOUT

JSON یا JSON Lines؟

برای داده‌های کوچک، JSON آرایه‌ای مناسب است، اما برای حجم‌های بزرگ توصیه می‌شود از JSON Lines استفاده کنید چون امکان نوشتن استریم و پردازش افزایشی را فراهم می‌کند و از بار زیاد حافظه جلوگیری می‌کند.

مثال JSON آرایه (برای داده‌های کوچک):

[
    { "name": "Color TV", "price": "1200" },
    { "name": "DVD player", "price": "200" }
]

مثال JSON Lines (هر خط یک شیء مستقل):

{"name": "Color TV", "price": "1200"}
{"name": "DVD player", "price": "200"}

مزیت‌ها:

  • JSON Lines اجازهٔ نوشتن incremental و تقسیم فایل‌ها را می‌دهد.
  • در پردازش دسته‌ای یا استریم، حافظه مصرفی پایین می‌ماند.

خروجی‌گیری از طریق خط فرمان

ساده‌ترین روش اضافه کردن فلگ -o یا -O به دستور scrapy crawl است.

scrapy crawl bookspider -o bookspider_data.json
scrapy crawl bookspider -o bookspider_data.jsonl
scrapy crawl bookspider -o file:///path/to/project/bookspider_data.json

تفاوت پرچم‌ها:

  • -o: اگر فایل وجود داشته باشد، آیتم‌های جدید را به آن الحاق می‌کند.
  • -O: فایل موجود را بازنویسی می‌کند.

نکات عملی: برای اجرای زمان‌بندی شده یا CI از این روش استفاده نکنید مگر کنترل نام فایل و رخدادهای overwrite را داشته باشید.

پیکربندی FEEDS در settings.py

روش مرتب‌تر کنترل خروجی استفاده از تنظیم FEEDS در settings.py است. این تنظیم یک دیکشنری می‌پذیرد که کلید آن URI فایل و مقدار آن دیکشنری تنظیمات مربوط به آن فید است.

# settings.py
FEEDS = {
    'data.jsonl': {'format': 'jsonlines'}
}

مثال تنظیم در داخل یک اسپایدر با custom_settings:

# bookspider.py
import scrapy
from myproject.items import BookItem

class BookSpider(scrapy.Spider):
    name = 'bookspider'
    start_urls = ['http://books.toscrape.com']

    custom_settings = {
        'FEEDS': {
            'data/bookspider.jsonl': {'format': 'jsonlines'},
        }
    }

    def parse(self, response):
        for article in response.css('article.product_pod'):
            book_item = BookItem(
                url=article.css('h3 > a::attr(href)').get(),
                title=article.css('h3 > a::attr(title)').get(),
                price=article.css('.price_color::text').get(),
            )
            yield book_item

در این مثال ورودی‌ها: پاسخ HTTP؛ خروجی: آیتم‌های تولیدشده که توسط Feed Exporter به فایل منتقل می‌شوند. خط به خط: گرفتن URL، عنوان و قیمت از CSS سلکتورها و ساختن آیتم.

گزینهٔ overwrite و پیش‌فرض‌ها

می‌توانید با افزودن کلید overwrite در تعریف FEEDS رفتار بازنویسی را کنترل کنید:

# settings.py
FEEDS = {
    'data.jsonl': {'format': 'jsonlines', 'overwrite': True}
}

پیش‌فرض در ذخیرهٔ محلی معمولاً overwrite=False است؛ بنابراین اگر قصد بازنویسی دارید صریحاً آن را تنظیم کنید.

نام‌گذاری داینامیک فایل‌ها

برای جلوگیری از جمع شدن همه داده‌ها در یک فایل، از قالب‌های جایگزین‌گذاری استفاده کنید مثل %(name)s و %(time)s. این پارامترها هنگام ایجاد فید با ویژگی‌های اسپایدر جایگزین می‌شوند.

FEEDS = {
    'data/%(name)s/%(name)s_%(time)s.jsonl': {'format': 'jsonlines'}
}

مثال نتیجه: data/bookspider/bookspider_2022-05-18T07-47-03.jsonl

بچ‌بندی فایل‌ها (batch_item_count)

برای تقسیم داده به قطعات مساوی از کلید batch_item_count استفاده کنید و یکی از placeholderهای %(batch_time)s یا %(batch_id)d را در نام فایل قرار دهید.

FEEDS = {
    'data/%(name)s/%(name)s_batch_%(batch_id)d.jsonl': {
        'format': 'jsonlines',
        'batch_item_count': 10
    }
}

با این تنظیم هر فایل حداکثر ۱۰ آیتم خواهد داشت و Scrapy هنگام رسیدن به حد جدید یک فایل جدید می‌سازد.

گزینه‌های تکمیلی و نکات عملکردی

مهم‌ترین کلیدهایی که ارزش تنظیم دارند:

  • encoding: مشخص کردن انکدینگ خروجی (مثلاً 'utf8').
  • fields: لیست فیلدهایی که می‌خواهید صادر شوند تا فقط دادهٔ لازم ذخیره شود.
  • item_classes و item_filter: برای محدود کردن نوع آیتم‌هایی که صادر می‌شوند.
  • indent: برای خواناتر کردن JSON های کوچک.
  • store_empty: آیا خروجی خالی باید ذخیره شود یا نه.
  • postprocessing: پلاگین‌های پس‌پردازشی مانند فشرده‌سازی یا ارسال به سرویس‌های ثالث.
  • item_export_kwargs: برای کنترل جزئیات export مثل export_empty_fields.

نکات عملکرد و امنیت:

  • برای دادهٔ بزرگ از JSON Lines و batch_item_count استفاده کنید تا حافظه را کنترل کنید.
  • احراز هویت برای S3/GCS را از طریق متغیرهای محیطی یا سرویس مدیریت اسرار نگه‌دارید؛ هرگز کلیدها را در ریپوزیتوری قرار ندهید.
  • برای خروجی‌های بحرانی، از تنظیم overwrite=False و نام‌گذاری داینامیک یا بررسی وجود فایل قبل از نوشتن استفاده کنید.
  • اگر سرعت تولید آیتم از سرعت نوشتن بیشتر شد، از صف‌ها یا سیستم ذخیره‌سازی همزمان استفاده کنید تا از افت یا از دست رفتن داده جلوگیری کنید.

جمع‌بندی

خلاصهٔ عملی: برای پروژه‌های کوچک می‌توانید با -o/-O شروع کنید، اما برای کنترل دقیق و production از FEEDS استفاده کنید. برای حجم‌های بالا همیشه jsonlines و batch_item_count را در نظر بگیرید، تنظیمات encoding و fields را استفاده کنید و کلیدهای محرمانه را ایمن نگه دارید.

مطالب مرتبط

مقاله‌های مرتبط