Scrapy + Postgresql + Django: Cấu hình kết nối và lưu dữ liệu qua Sqlalchemy

Mặc định bạn đã có Scrapy với spinder đang hoạt động và Postgresql đang hoạt động với Django đã được cài đặt trên máy. Vì vậy, để ngắn gọn hơn, ở bài này sẽ tập chung vào cách kết nối và lưu dữ liệu Scrapy đến Postgresql dựa trên dữ liệu sẵn có của django.

Cài đặt Sqlalchemy nếu chưa có:

pip install SQLAlchemy

Mục tiêu bạn sẽ đạt được: Crawl dữ liệu → Postgresql → Django :tada:

Yêu cầu:

  1. Ứng dụng django (shop, blog…) với Postgresql
  2. Scrapy có thể Crawldữ liệu shop, blog tương ứng

(Nếu chưa có django, bạn sẽ phải tự động thêm data, bảng, và cột theo cách thủ công + google)

Bên dưới mình sẽ ví dụ về Spinder sẽ Crawl dữ liệu từ một webshop trên internet sau đó lưu dữ liệu vào database của ứng dụng Shop Django, để chính Django có thể sử dụng dữ liệu đó và hiển thị nó lại trên internet.

I. Giả sử, Django và Scrapy của bạn có các file cần lưu ý như sau:

Django

1. Tệp models.py - ứng dụng shop:

# (django)/shop/models.py
...
class Product(models.Model):
    title = models.CharField(max_length=200)
    slug = models.SlugField(max_length=200, unique=True)
    image = models.ImageField(upload_to='product_images', default='no-image.jpg')
    price = models.PositiveIntegerField(default=0, null=True,) 
    details = models.TextField(blank=True, null=True)
    brand = models.ForeignKey(Brand, blank=True, null=True, on_delete=models.CASCADE)
    ...
    status = models.BooleanField(default=True)
    is_featured = models.BooleanField(default=False)
....

2. Tệp settings.py - dự án django

# (django)/settings.py
....
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'NAME': 'data',  # tên database
        'USER': 'user',  # user của data
        'PASSWORD': 'pass',  # passcuar data
        'HOST': 'localhost',
        'PORT': '5432',
    }
}
...

Scrapy

Tệp items.py

...
class PricenaProduct(scrapy.Item):
    slug = scrapy.Field()
    title = scrapy.Field()
    price = scrapy.Field()
    details = scrapy.Field()
    image = scrapy.Field()
    ...
...

II. Cấu hình kết nối Scrapy - PostgreSql

1. Thêm thông tin của Postgresql trong file settings.py của Scrapy

# (scrapy)/settings.py
...
# cấu hình pipelines
ITEM_PIPELINES = {
    "aznet.pipelines.AznetPipeline": 300,
    "aznet.pipelines.DemoPipeline": 300,
}
...
# kết nối database
DATABASE = {
    'drivername': 'postgresql',
    'database': 'data',  # data name
    'username': 'user',  # user for data
    'password': 'pass',  # pass
    'port': '5432', 
}
  • DATABASE: Những thông tin này trùng với thông tin database trong file settings.py của Django, chỉ khác tên drivernamehost
  • ITEM_PIPELINES: Nếu bạn tùy biến class trong file pipelines.py, thì phải thêm tương ứng ở đây

2. Tạo file models.py

(cùng thư mục với file settings.py scrapy)

# (scrapy)/models.py
from sqlalchemy import Column, Integer, String, create_engine, Boolean
from sqlalchemy.engine.base import Engine
from sqlalchemy.engine.url import URL
from sqlalchemy.ext.declarative import declarative_base

from . import settings

DeclarativeBase = declarative_base()

def db_connect() -> Engine:
    """
    Tạo kết nối cơ sở dữ liệu bằng cách sử dụng cài đặt cơ sở dữ liệu từ settings.py.
    Trả về phiên bản công cụ sqlalchemy
    """
    return create_engine(URL(**settings.DATABASE))

def create_items_table(engine: Engine):
    """
    Tạo bảng Items
    """
    DeclarativeBase.metadata.create_all(engine)

class Items(DeclarativeBase):
    """
    Xác định mô hình Items
    """

    __tablename__ = "shop_product"  
    """
    Tên bảng trong data postgresql muốn lưu dữ liệu Crawl
    Các cột bên trong tham chiếu từ (django)/models.py
    """
    id = Column(Integer, primary_key=True)
    slug = Column("slug", String, unique=True)
    title = Column("title", String)
    price = Column("price", Integer, default=0)
    details = Column("details", String)
    image = Column("image", String)
    status = Column("status", Boolean, default=True)
    is_featured = Column("is_featured", Boolean, default=False)

Giải thích một chút về file models.py bên trên:
Phần cần chú ý là class: class Items(DeclarativeBase):
Ở đây bạn sẽ xác định bảng muốn lưu dữ liệu và các cột của bảng. Nên so sánh với tệp models.py của django.

  • id: đây là trường tự động được tạo trong csdl sql và nó chứa primary_key=True. Vì vậy nó là bắt buộc phải có trong scrapy. Nếu postgresql của bạn xác định cột khác là primary_key, thì bạn cũng phải xác định primary_key=True trong trường tương ứng.

  • Các trường khác thiết lập thông số tương ứng và là bắt buộc phải có dù bạn có Crawl nó hoặc không (ví dụ trường: slug, status, is_featured…).
    Có ngoại lệ đó là các trường(cột) trong data có giá trị null mặc định, thì không cần thêm ở đây, (ví dụ: brand).

3. Tệp pipelines.py - kết nối và lưu dữ liệu khi Crawl

# (scrapy)/pipelines.py
from sqlalchemy.orm import sessionmaker
from .models import Items, create_items_table, db_connect

class AznetPipeline:  # thay đổi phù hợp với bạn
    def __init__(self):
        """
        Khởi tạo kết nối cơ sở dữ liệu và trình tạo phiên.
        Tạo bảng Items.
        """
        engine = db_connect()
        create_items_table(engine)
        self.Session = sessionmaker(bind=engine)

    def process_item(self, item, spider):
        """
        Xử lý Items và lưu trữ vào cơ sở dữ liệu.
        """
        session = self.Session()
        instance = session.query(Items).filter_by(**item).one_or_none()
        if instance:
            return instance
        aznet_item = Items(**item)

        try:
            session.add(aznet_item)
            session.commit()
        except:
            session.rollback()
            raise
        finally:
            session.close()

        return item

Đảm bảo rằng tên các Item trong Spinder của bạn trùng khớp với tên các cột trong database của Django nhé.

Bây giờ hãy chạy Crawl của bạn để xem dữ liệu đã được lưu vào database chưa nhé.

III. Kết luận:

Trên đây là cách kết nối cơ sở dữ liệu PostgreSQL với Scrapy, sử dụng Sqlalchemy. Mục đích là lưu dữ liệu sau đó sử dụng lại dữ liệu đó với Django.
Do đó bạn cần phải đồng bộ giữa các tên của Items, tên cột của bảng (file models.py) và tên cột thực tế trong cơ sở dữ liệu.
Đặc biệt chú ý về giá trị, mối quan hệ bên trong các cột của csdl.