خانه/مقالات/ذخیره‌سازی در اسکریپینگ با Scrapy
برنامه نویسی
استخراج داده
برگشت به صفحه مقاله ها
ذخیره‌سازی در اسکریپینگ با Scrapy

ذخیره‌سازی در اسکریپینگ با Scrapy

این راهنما به‌صورت گام‌به‌گام روش‌های متداول ذخیره‌سازی داده در اسکریپینگ با Scrapy را پوشش می‌دهد: خروجی‌گیری به JSON/CSV، ارسال به S3 و ذخیره در MySQL/Postgres با استفاده از Item Pipelines. نکات امنیتی، عملکردی و نمونه‌کدهای عملی برای استفاده در پروژه‌های واقعی ارائه شده است.
آسان اسکریپ
آسان اسکریپ
1404-12-12

مقدمه

این مقاله عملی و مرحله‌به‌مرحله به شما نشان می‌دهد چطور داده‌های استخراج‌شده با Scrapy را ذخیره کنید. پس از خواندن این مطلب می‌دانید چه روش‌هایی برای خروجی‌گیری (فایل‌های CSV/JSON، S3، یا پایگاه‌داده) وجود دارد، چه نکات امنیتی و عملکردی را باید رعایت کنید و چگونه یک Item Pipeline برای ذخیره در MySQL یا PostgreSQL بنویسید.

استفاده از Feed Exporters

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

  • فرمت‌های رایج خروجی: JSON، CSV، XML و pickle.
  • محل ذخیره: فایل محلی، FTP، Amazon S3، Google Cloud Storage یا استاندارد خروجی (stdout).

Feed Exporter مناسب کارهای ساده یا زمانی است که نیاز به پردازش پیچیده روی هر آیتم ندارید. برای منطق ذخیره‌سازی پیشرفته‌تر از Item Pipelines استفاده کنید.

ذخیره به فرمت JSON یا CSV

برای کارهای ساده و یک‌باره می‌توانید از فلگ‌های خط فرمان استفاده کنید. توجه کنید بین -o و -O تفاوت وجود دارد: -o به خروجی اضافه می‌کند (append) و -O فایل را بازنویسی (overwrite) می‌کند.

مثال ذخیره به JSON:

scrapy crawl chocolatespider -o my_scraped_chocolate_data.json

مثال ذخیره با مسیر کامل و نوع مشخص:

scrapy crawl chocolatespider -O file:///path/to/project/my_scraped_chocolate_data.json:json

ذخیره به CSV:

scrapy crawl chocolatespider -o my_scraped_chocolate_data.csv
# یا با مسیر کامل
scrapy crawl chocolatespider -O file:///path/to/project/my_scraped_chocolate_data.csv:csv

نکات عملی:

  • اگر تعداد زیادی آیتم دارید و حافظه مهم است، از فرمت jsonlines (.jl) استفاده کنید تا هر آیتم در یک خط ذخیره شود و نیازی به بارگذاری کل لیست در حافظه نباشد.
  • برای فایل‌های CSV به encoding (معمولاً UTF-8) و علامت‌گذاری کاراکترها توجه کنید تا کاراکترهای فارسی و نمادها به‌درستی ذخیره شوند.

ذخیره مستقیم به Amazon S3

برای ارسال خروجی مستقیم به S3 باید یکی از کتابخانه‌های AWS مثل botocore یا boto3 را نصب کنید. با این کار می‌توانید URI مقصد را با قالب s3:// مشخص کنید. مثال نصب:

pip3 install botocore

مثال اجرای کرال و ارسال خروجی به S3 (پارامترها را با مقادیر خودتان جایگزین کنید):

scrapy crawl chocolatespider -O s3://AWS_KEY:AWS_SECRET@mybucket/path/myscrapeddata.csv:csv

روش امن‌تر: ذخیره کردن کلیدها در فایل تنظیمات پروژه:

AWS_ACCESS_KEY_ID = 'myaccesskeyhere'
AWS_SECRET_ACCESS_KEY = 'mysecretkeyhere'

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

  • هرگز کلیدها را در ریپازیتوری عمومی قرار ندهید؛ بهتر است از متغیرهای محیطی (Environment Variables) یا نقش‌های IAM (در صورت اجرای روی EC2 یا سرویس‌های مدیریت‌شده) استفاده کنید.
  • Feed Exporter برای S3 از delayed file delivery استفاده می‌کند: ابتدا فایل محلی ساخته می‌شود و پس از پایان اجرا به S3 آپلود می‌شود؛ پس در صورت کرش یا قطع شدن فرایند موقتاً فایل ممکن است ناقص باشد.

ذخیره در MySQL: Item Pipeline گام‌به‌گام

برای ذخیره در پایگاه‌داده بهتر است از Item Pipelines استفاده کنید تا هر آیتم هنگام استخراج، پردازش و ذخیره شود. مراحل کلی:

  1. نصب درایور مربوطه (mysql-connector-python یا هر درایور مناسب).
  2. ایجاد جدول در پایگاه‌داده.
  3. نوشتن کلاس Pipeline با متدهای create_connection، process_item و ذخیره‌ساز.

نمونه DDL برای ایجاد جدول (مثال):

CREATE TABLE IF NOT EXISTS chocolate_products (
    id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(255),
    price VARCHAR(255),
    url TEXT
);

نمونه پیاده‌سازی ساده Pipeline برای MySQL (پارامترها را از متغیرهای محیطی بخوانید؛ هرگز مقادیر را هاردکد نکنید):

import mysql.connector
import os

class SavingToMySQLPipeline(object):
    def __init__(self):
        self.create_connection()

    def create_connection(self):
        # ورودی‌ها: پارامترهای اتصال از محیط یا settings
        self.connection = mysql.connector.connect(
            host=os.getenv('DB_HOST', 'localhost'),
            user=os.getenv('DB_USER', 'root'),
            password=os.getenv('DB_PASS', ''),
            database=os.getenv('DB_NAME', 'chocolate_scraping')
        )
        self.curr = self.connection.cursor()

    def process_item(self, item, spider):
        # این متد توسط Scrapy برای هر آیتم صدا زده می‌شود
        self.store_db(item)
        return item

    def store_db(self, item):
        # استفاده از query پارامتری برای جلوگیری از SQL injection
        sql = "INSERT INTO chocolate_products (name, price, url) VALUES (%s, %s, %s)"
        values = (item.get('name'), item.get('price'), item.get('url'))
        self.curr.execute(sql, values)
        self.connection.commit()

توضیح خط‌ها:

  • create_connection: اتصال به DB را برقرار می‌کند؛ بهتر است از متغیرهای محیطی استفاده کنید.
  • process_item: نقطه ورود Scrapy که مسئول فوروارد آیتم به تابع ذخیره است و در پایان باید آیتم را بازگرداند.
  • store_db: اجرای دستور INSERT به‌صورت پارامتری و commit برای ثبت تغییرات.

نکات عملی برای MySQL:

  • برای بارگذاری تعداد زیاد آیتم، از batch insert (جمع‌آوری چند آیتم و insert گروهی) استفاده کنید تا عملکرد بهتری داشته باشید.
  • در سناریوهای حساس به تأخیر، استفاده از صف (مثلاً Redis یا Kafka) و سپس مصرف‌کننده‌ای برای نوشتن در DB می‌تواند پایایی را افزایش دهد.

ذخیره در PostgreSQL: Pipeline و تفاوت‌ها

برای PostgreSQL باید درایور psycopg2 را نصب کنید و در queryها دقت کنید که placeholderها در psycopg2 هم از %s استفاده می‌کنند.

pip install psycopg2

نمونه اتصال و pipeline برای PostgreSQL:

import psycopg2
import os

class SavingToPostgresPipeline(object):
    def __init__(self):
        self.create_connection()

    def create_connection(self):
        self.connection = psycopg2.connect(
            host=os.getenv('DB_HOST', 'localhost'),
            database=os.getenv('DB_NAME', 'chocolate_scraping'),
            user=os.getenv('DB_USER', 'postgres'),
            password=os.getenv('DB_PASS', '')
        )
        self.curr = self.connection.cursor()

    def process_item(self, item, spider):
        self.store_db(item)
        return item

    def store_db(self, item):
        try:
            self.curr.execute(
                "INSERT INTO chocolate_products (name, price, url) VALUES (%s, %s, %s)",
                (item.get('name'), item.get('price'), item.get('url'))
            )
            self.connection.commit()
        except Exception as e:
            # لاگ‌برداری خطا و rollback در صورت لزوم
            print(e)
            self.connection.rollback()

نکات خاص PostgreSQL:

  • برای بارگذاری بالا، استفاده از COPY یا کتابخانه‌هایی مثل psycopg2.extras.execute_batch می‌تواند کارایی را به‌طور قابل‌توجهی افزایش دهد.
  • در عملیات حساس به سازگاری داده، از تراکنش‌ها و rollback استفاده کنید.

مدیریت Pipelines و تنظیمات

پس از نوشتن Pipeline فراموش نکنید آن را در settings.py ثبت کنید تا Scrapy آن را اجرا کند. مثال:

ITEM_PIPELINES = {
    'chocolatescraper.pipelines.PriceToUSDPipeline': 100,
    'chocolatescraper.pipelines.DuplicatesPipeline': 200,
    'chocolatescraper.pipelines.SavingToMySQLPipeline': 300,
}

ترتیب عددی مشخص‌کننده اولویت اجرا است؛ عدد پایین‌تر زودتر اجرا می‌شود.

نکات عملکردی، امنیتی و پایداری

  • هرگز رمز عبور یا کلیدها را در کد هاردکد نکنید؛ از متغیرهای محیطی یا سرویس‌های مدیریت محرمانگی استفاده کنید.
  • برای جریان‌های داده با حجم بالا از batching، queue، یا سرویس‌های استریم استفاده کنید تا فشار روی پایگاه‌داده کاهش یابد.
  • در عملیات نوشتن به S3 یا DB، مدیریت خطا (retries با backoff)، لاگ‌گیری و بررسی وضعیت نهایی را پیاده کنید تا از از دست رفتن داده جلوگیری شود.
  • از اتصال‌های پایدار یا connection pool استفاده کنید تا سربار ایجاد و بستن اتصال به حداقل برسد.

جمع‌بندی و قدم‌های بعدی

خلاصه: اگر نیاز به خروجی ساده دارید از Feed Exporter استفاده کنید؛ برای منطق ذخیره‌سازی پیچیده، پاکسازی پیشرفته یا ذخیره در DB بهتر است از Item Pipelines بهره ببرید. برای ارسال به S3 از کتابخانه AWS مناسب و مکانیسم‌های امن نگهداری کلیدها استفاده کنید. در نهایت عملکرد و پایداری را با batching، retry و استفاده از نقش‌های IAM/متغیرهای محیطی بهبود دهید.

قدم بعدی منطقی شما می‌تواند مدیریت User-Agentها، پراکسی‌ها و استقرار (deployment) کرال‌ها باشد تا ربات‌تان در محیط تولیدی پایدار و امن اجرا شود.

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