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
Yêu cầu:
- Ứng dụng django (shop, blog…) với Postgresql
- 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ề [color=red]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.[/color]
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.pycủa Django, chỉ khác têndrivernamevàhost - 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 địnhprimary_key=Truetrong 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.