Scrape (trích xuất) dữ liệu tự động với Scrapy
Trong 1 bài trước đây, mình đã nói qua về scrape dữ liệu bằng PHP và regular expression. Vừa rồi mình có thực hiện scrape data từ VNExpress giùm 1 người bạn, xài thử Scrapy và thấy cũng khá hiệu quả nên chia sẻ với mọi người
Ưu điểm của Scrapy là cung cấp sẵn 1 cấu trúc tương đối hoàn chỉnh để thực hiện việc crawl và scrape data, người dùng chỉ cần bổ sung thêm định nghĩa về dữ liệu cần lấy là xong (ví dụ như URL bắt đầu là gì, link chuyển qua trang mới là gì, các thông tin cần lấy ở mỗi trang là gì)
1. Sau khi cài Scrapy và các thư viện liên quan, chạy lệnh sau
scrapy startproject tutorial
Scrapy sẽ tạo 1 project hoàn chỉnh
2. Các file quan trọng
a) items.py - chứa định nghĩa thông tin mình muốn extract
from scrapy.item import Item, Field
class VNExpressItem(Item):
# define the fields for your item here like:
title = Field()
url = Field()
content = Field()
author = Field()
writtenOn = Field()
tags = Field()
catid = Field()
postid = Field()
b) file spiders (trong thư mục spiders), định nghĩa cách chuyển giữa các trang và cách lấy thông tin. ví dụ định nghĩa domain thực hiện việc scrape
name = "vnexpress"
allowed_domains = ["vnexpress.net"]
start_urls = [
"http://m.vnexpress.net/thegioi/the-gioi/1001002/p1/2411014/0"
]
Ở đây có 1 điểm cần chú ý là mình scrape phiên bản mobile (http://m.vnexpress.net) thay vì bản full. Lí do là bản mobile thì dung lượng cần tải về gọn hơn và cấu trúc thì nhẹ hơn và ít thay đổi hơn bản bình thường.
Định nghĩa đường dẫn qua trang tiếp theo, dùng XPath
next_page = hxs.select("//a[@class='right txt_1_1em']/@href").extract()
đoạn ở trên sẽ tương ứng với phần HTML sau
xử lí từng post
for post in posts:
postTitle = post.select('.//h2[@class="h2SdTopHome txt_1_5em"][1]/text()').extract()
itemFullURL = base_url + post.select('.//@href').extract()[0]
request = Request(itemFullURL,callback=self.parse_full_post)
request.meta['title'] = postTitle
request.meta['url'] = itemFullURL
yield request
Ở đây, itemFullURL là URL của từng bài báo. Scrapy sẽ tạo 1 request mới để đọc URL này, đồng thời trả về phần callback là 1 function (parse_full_post) nhằm tiếp tục thực hiện việc trích xuất dữ liệu trong bài báo kia
đây là function parse_full_post
def parse_full_post(self, response):
fullPost = HtmlXPathSelector(response)
post_content = fullPost.select('.//div[@class="fck_detail pNormalD fontSizeCss left"][1]').extract()
post_time = fullPost.select('.//div[@class="art_time left"][1]').extract()
post_tags = fullPost.select('.//meta[@name="keywords"][1]/@content').extract()
post_author = fullPost.select('.//p[@class="Normal"][last()]').extract()
cat_id = fullPost.select('.//meta[@name="tt_category_id"][1]/@content').extract()
post_id = fullPost.select('.//meta[@name="tt_article_id"][1]/@content').extract()
item = VNExpressItem()
item['title'] = response.meta['title']
item['url'] = response.meta['url']
item['content'] = post_content
item['writtenOn'] = post_time
item['tags'] = post_tags
item['author'] = post_author
item['catid'] = cat_id
item['postid'] = post_id
yield item
ở đây ta thực hiện việc lấy các dữ liệu cần thiết (title, content, writtenOn v.v....)
nếu đến đây thì bạn đã có thể chạy Scrapy và cho xuất dữ liệu ra theo dạng CSV hay JSON bằng cú pháp sau
scrapy crawl VNExpress -o output.json -t json
c) nếu muốn insert các kết quả tìm được vào database thì sử dụng tiếp phần pipeline (file pipelines.py)
def process_item(self, item, spider):
try:
self.cursor.execute("""INSERT INTO article_stub (title, url, content, post_time, tags, author, catid, postid) VALUES (%s, %s, %s, %s, %s, %s, %s, %s)""",
(
item['title'][0].encode('utf-8'), #item['title'].encode('utf-8'),
item['url'].encode('utf-8'), #item['url'].encode('utf-8')
item['content'][0].encode('utf-8'),
item['writtenOn'][0].encode('utf-8'),
item['tags'][0].encode('utf-8'),
item['author'][0].encode('utf-8'),
item['catid'][0].encode('utf-8'),
item['postid'][0].encode('utf-8')
)
)
self.conn.commit()
return item
phần chính trong pipeline là function process_item, function này sẽ chạy cho mỗi đơn vị thông tin (trong bài viết này thì là bài báo) được trích xuất
3. Tóm tắt:
Đây là sourcecode của script dùng để scrape VNExpress, mình chạy script này scrape toàn bộ bài viết trong 1 chuyên mục (Xã hội), bao gồm khoảng 50,000 bài báo mất khoảng 6 tiếng