Giới thiệu/hướng dẫn về Crawler với Scrapy Framework (Phần 3)

Trong phần 2 mình đã hướng dẫn cách tạo project, tạo 1 spider cũng như extract dữ liệu. Trong phần này, mình sẽ hướng dẫn cách sử dụng pipelines để lưu vào databases, viết các spider sao cho gọn và nhanh hơn.

1. Lưu dữ liệu vào databases

Edit file pipelines.py như sau

# -*- coding: utf-8 -*-

# Define your item pipelines here
#
# Don't forget to add your pipeline to the ITEM_PIPELINES setting
# See: http://doc.scrapy.org/en/latest/topics/item-pipeline.html
from pymongo import MongoClient


class ScraperPipeline(object):
    def __init__(self):
        self.collection = connect_db("crawler")["news"]

    def process_item(self, item, spider):
        self.collection.insert_one(item)                #save to databases
    return item


    def connect_db(db_name):
        return MongoClient("mongodb://localhost:27017")[db_name]

Đoạn trên là mình sử dụng MogoDB để lưu dữ liệu. Các bạn có thể tìm hiểu cách cài đặt MongoDB và module pymongo cho python Chỉnh sửa lại file sohoavnexperss.py để trả về article chứ không in ra màn hình nữa

# -*- coding: utf8 -*-
import scrapy


class SohoaVnexpressNet(scrapy.Spider):
    name = "sohoa"

    def start_request(self):
        urls = [
            'https://sohoa.vnexpress.net/tin-tuc/doi-song-so/tap-chi-co-chu-ky-steve-jobs-duoc-ban-gia-50-000-usd-3662652.html',
        ]
        for url in urls:
            yield scrapy.Request(url=url, callback=self.parse_artilce)

    def parse_artilce(self, response):
        artilce = {}
        artilce['title'] = response.xpath('//*[@id="col_sticky"]/h1/text()').extract()[0].encode('utf-8').strip()
        artilce['description'] = response.xpath('//*[@id="col_sticky"]/h2').extract()[0].encode('utf-8').strip()
        artilce['content'] = response.xpath('//*[@id="col_sticky"]/article').extract()[0].encode('utf-8').strip()
        artilce['author'] = response.xpath('//*[@id="col_sticky"]/article/p[5]/strong/text()').extract()[0].encode('utf-8').strip()
        artilce['publish_date'] = response.xpath('//*[@id="col_sticky"]/header/span/text()').extract()[0].encode('utf-8').strip()
        # for key, text in artilce.iteritems():
        #     print "{key}: {text}".format(key = key.upper(), text = text)
        return artilce

Tiếp theo sửa file settings.py để sử dụng pipelines, add thêm dòng sau:

ITEM_PIPELINES = {'scraper.pipelines.ScraperPipeline': 1}

Sau đó chạy lại lệnh sau:

scrapy crawl sohoa

ta sẽ thấy dữ liệu được đẩy vào MongoDB

2. Tối ưu tạo spiders

Sử dụng Item của scrapy để định nghĩa một Article Viết lại file items.py như sau:

# -*- coding: utf-8 -*-

# Define here the models for your scraped items
#
# See documentation in:
# http://doc.scrapy.org/en/latest/topics/items.html

import scrapy


class ScraperItem(scrapy.Item):
    # define the fields for your item here like:
    title = scrapy.Field()
    description = scrapy.Field()
    content = scrapy.Field()
    author = scrapy.Field()
    publish_date = scrapy.Field()

Như cách hiện tại, mỗi khi thêm 1 site ta sẽ thêm 1 file python vào thư mục spiders và sẽ lặp lại đoạn code parse_artilce, như vậy sẽ gây trùng lặp code. Ta sẽ tạo 1 class DetailScraper để viết phần parse_aritlce kia và các spider sau này sẽ extend class DetailScraper Tạo file sau spiders/detail_scraper.py và sử dụng ScraperItem

# -*- coding: utf8 -*-
import scrapy
from items import ScraperItem


class DetailScraper(scrapy.Spider):
    name = None
    urls = []
    xpaths = {}

    def start_request(self):
        for url in urls:
            yield scrapy.Request(url=url, callback=self.parse_artilce)

    def parse_artilce(self, response):
        artilce = ScraperItem()
        for key in self.xpaths.keys:
            artilce[key] = response.xpath(self.xpaths[key]).extract()[0].encode('utf-8').strip()
        return artilce

Giờ đây, file spider chỉ còn chứa các thông tin về name, urls, các xpath để extract ra dữ liệu

# -*- coding: utf8 -*-
from detail_scraper import DetailScraper


class SohoaVnexpressNet(DetailScraper):
    name = "sohoa"
    urls = [
            'https://sohoa.vnexpress.net/tin-tuc/doi-song-so/tap-chi-co-chu-ky-steve-jobs-duoc-ban-gia-50-000-usd-3662652.html',
        ]
    xpaths = {
        "title": '//*[@id="col_sticky"]/h1/text()',
        "description": '//*[@id="col_sticky"]/h2',
        "content": '//*[@id="col_sticky"]/article',
        "author": '//*[@id="col_sticky"]/article/p[5]/strong/text()',
        "publish_date": '//*[@id="col_sticky"]/header/span/text()'
    }
    def __init__(self):
        DetailScraper.__init__(self)

Nhìn file sohoavnexpress.py gọn gàng hơn rất nhiều phải không nào.

3. Tổng kết

Vậy, mình đã hướng dẫn các bạn cách sử dụng pipelines của scrapy để lưu dữ liệu vào databases cũng như cách tối ưu code cho mỗi con spider. Hẹn gặp lại các bạn trong bài viết sau.