Giới thiệu/hướng dẫn về Crawler với Scrapy Framework (Phần 3)
Bài đăng này đã không được cập nhật trong 6 năm
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.
All rights reserved