Nói tới đây có thể sẽ có bạn hỏi thu thập dữ liệu là gì, để làm gì, sao phải Cào dữ liệu với Scrapy để thu thập dữ liệu? Để giải thích dễ dàng thì sẽ đặt ra một bài toán sau: “Bạn cần xây một trang web/ứng dụng tổng hợp những tin tức thời sự được đăng trên các trang báo như Vnexpress, Dantri, Genk… tương tự như thằng Baomoi ấy”. Vậy để giải bài toán này thì chúng ta cần có đầu vào là các bài báo được đăng trên các trang kia, khi đó, chúng ta cần dùng Scrapy để thu thập các bài báo. Để viết được một ứng dụng thu thập dữ liệu bằng Scrapy thì trước tiên chúng ta nên tìm hiều qua về Scrapy có những thành phần gì, cách thức hoạt động của nó.
1. Thành phần
Scrapy Engine
Scrapy Engine có trách nhiệm kiểm soát luồng dữ liệu giữa tất cả các thành phần của hệ thống và kích hoạt các sự kiện khi một số hành động xảy ra
Scheduler
Giống như một hàng đợi (queue), scheduler sắp xếp thứ tự các URL cần download
Dowloader
Thực hiện dowload trang web và cung cấp cho engine
Spiders
Spiders là class được viết bởi người dùng, chúng có trách nhiệm bóc tách dữ liệu cần thiết và tạo các url mới để nạp lại cho scheduler qua engine.
Item Pipeline
Những dữ liệu được bóc tách từ spiders sẽ đưa tới đây, Item pipeline có nhiệm vụ xử lý chúng và lưu vào cơ sở dữ liệu
Các Middlewares
Là các thành phần nằm giữa Engine với các thành phần khác, chúng đều có mục địch là giúp người dùng có thể tùy biến, mở rổng khả năng xử lý cho các thành phần. VD: sau khi dowload xong url, bạn muốn tracking, gửi thông tin ngay lúc đó thì bạn có thể viết phần mở rộng và sửa lại cấu hình để sau khi Dowloader tải xong trang thì sẽ thực hiện việc tracking.
a. Spider middlewares
Là thành phần nằm giữa Eninge và Spiders, chúng xử lý các response đầu vào của Spiders và đầu ra (item và các url mới).
b. Dowloader middlewares
Nằm giữa Engine và Dowloader, chúng xử lý các request được đẩy vào từ Engine và các response được tạo ra từ Dowloader
c. Scheduler middlewares
Nằm giữa Engine và Scheduler để xử lý những requests giữa hai thành phần
2. Luồng dữ liệu

- Khi bắt đầu crawl một website, Engine sẽ xác định tên miền và tìm vị trí của spider đó và yêu cầu spider đó tìm các urls đầu tiên để crawl
- Engine nhận danh sách các urls đầu tiên từ spider, gửi cho Scheduler để sắp xếp
- Engine yêu cầu danh sách cách urls tiếp theo từ Scheduler
- Engine nhận danh sách các url tiếp theo từ Scheduler vào gửi đến Dowloader (requests)
- Downloader nhận request và thực hiện việc tải trang, sau khi tải xong sẽ tạo một response và gửi lại Engine
- Respone từ Dowloader sẽ được Engine đẩy qua Spiders để xử lý
- Tại Spiders, khi nhận được response, chúng bóc tách thông tin từ response (tilte, content, author, date publish…) và những url có khả năng để crawl và đẩy lại cho Engine (requests)
- Ở bước này, Engine nhận được kết quả từ Spiders sẽ thực hiện 2 công việc: đẩy những dữ liệu đã được bóc tách tới Item Pipeline để xử lý và lưu vào Databases, đẩy những url mới (requests) mới về Scheduler và quay về bước 3
Thực hành
Ở phần trước tôi đã giới thiệu với các bạn về thành phần và luồng hoạt động của Scrapy Framwork, tới phần này tôi sẽ hướng dẫn các bạn cài đặt và sử dụng Scrapy để crawl tin tức ở trang https://sohoa.vnexpress.net/
1. Cài đặt
Tôi sẽ sử dụng virtualenv và cài đặt thông qua pip. Nếu các bạn chưa biết về chúng thì có thể tìm hiểu trên mạng và cài đặt chúng. Trước tiên tạo file requirements.txt:
touch requirements.txt
hoặc
pip freeze > requirements.txt
Mở file requirements.txt và thêm các thư viện sau:
lxml
parsel
w3lib
twisted
cryptography
pyOpenSSL
Scrapy
Save lại và chạy:
pip install -r requirements.txt
Vậy là chúng ta đã cài đặt xong Scrapy rồi đấy.
2. Bắt đầu Cào dữ liệu với Scrapy
1. Tạo project Scrapy
- Việc cài đặt python, thư viện scrapy các bạn follow trên trang chủ scrapy: http://doc.scrapy.org/en/latest/intro/install.html trên này đã hướng dẫn từng bước cho các bạn cài đăt.
- Tiếp theo chúng ta sẽ tạo một project mà đặt tên nó là crawler với câu lệnh sau:
scrapy startproject crawler
khi đó project chúng ta vừa tạo sẽ có cấu trúc như sau:
crawler/
crawler/ # project's Python module, you'll import your code from her
spiders/ # a directory where you'll later put your spiders
__init__.py
__init__.py
items.py # project items definition file
middlewares.py # project middlewares file
pipelines.py # project pipelines file
settings.py # project settings file
scrapy.cfg # deploy configuration file
Sau khi tạo xong chạy các bạn lên trang https://www.thegioididong.com/ và chọn một sản phẩm bất kì muốn crawl comments. Ví dụ khi vào link: https://www.thegioididong.com/dtdd/samsung-galaxy-a50
Bây giờ đến bước crawl comment về
B1. Trong file items.py chúng ta sẽ viết code thêm như sau:
import scrapy
class CrawlerItem(scrapy.Item):
# define the fields for your item here like:
User = scrapy.Field()
Comment = scrapy.Field()
Time = scrapy.Field()
time, content, user là các trường muốn crawl : tương ứng là thời gian bình luận, nội dung bình luận, và tên người bình luận .
B2. Trong spiders/ tạo một file tên là crawler_spider.py với nội dung như sau:
from scrapy import Spider
from scrapy.selector import Selector
from crawler.items import CrawlerItem
class CrawlerSpider(Spider):
name = "crawler"
allowed_domains = ["thegioididong.com"]
start_urls = [
"https://www.thegioididong.com/dtdd/samsung-galaxy-a50",
]
def parse(self, response):
questions = Selector(response).xpath('//ul[@class="listcomment"]/li')
for question in questions:
item = CrawlerItem()
item['User'] = question.xpath(
'div[@class="rowuser"]/a/strong/text()').extract_first()
item['Comment'] = question.xpath(
'div[@class="question"]/text()').extract_first()
item['Time'] = question.xpath(
'div[@class="actionuser"]/a[@class="time"]/text()').extract_first()
yield item
ul[@class=”listcomment”]/li => Inspect để xem cấu trúc html trong thẻ <ul class=”listcomment”> bên trong có các thẻ li, mỗi li chứa thông tin 1 bình luận.
Inspect 1 thẻ li chứa comment nó sẽ có cấu trúc như sau:
<li class="comment_ask" id="33467716">
<div class="rowuser">
<a href="javascript:void(0)"><div>h</div><strong onclick="selCmt(33467716)">Nguyen Thi Ngan Ha</strong></a>
</div>
<div class="question">Hiện tại có máy chưa ạ</div>
<div class="actionuser" data-cl="0"><a href="javascript:void(0)" class="respondent" onclick="cmtaddreplyclick(33467716)">Trả lời</a>
<a href="javascript:void(0)" class="time" onclick="cmtReport(33467716)">1 phút trước </a>
</div>
<div class="replyLate">Quản trị viên sẽ phản hồi bình luận của chị Nguyen Thi Ngan Ha trong vòng 15 phút.</div>
<div class="listreply hide" id="r33467716"></div><div class="inputreply hide"></div>
</li>
div[@class=”rowuser”]/a/strong/text() => lấy tên người bình luận
div[@class=”question”]/text() => lấy nội dung bình luận
div[@class=”actionuser”]/a[@class=”time”]/text() => lấy thời gian bình luận
B3. Giờ muốn xuất ra một file lưu giữ liệu tên là comments tôi sẽ chạy lệnh sau
//file json:
scrapy crawl crawler -o comments.json
//hoặc file csv:
scrapy crawl crawler -o comments.csv
Kết quả file json export được:

Trang tgdd phân trang 10 bản ghi đầu nên mới lấy data của trang đầu tiên, sau khi decode thì được như ảnh trên.
Vậy là tôi đã hướng dẫn các bạn Cào dữ liệu với Scrapy thông quá ví dụ về lấy bình luận trên trang tgdd rồi, còn những bình luận trong phân trang các bạn có thể tìm hiểu các để crawl thêm nhé
Thấy hay và hũu ích hãy share với mọi người cùng đọc nhé ! Xem thêm tại : luulam.dev