Scrapy 學習

Scrapy Tutorial 剝指南

係呢個指南,我哋假設 Scrapy 已經在你的系統。如果『不是事實 not the case』,睇 Installation guide。

我們會『剝scrapy』quotes.toscrape.com,個網站列出不少嚟自名作家的名言。

這個指南會『帶你行/耐心地示範 walk you through』呢啲任務:

  1. 創建一個新的 Scrapy 工程
  2. 寫一個『蜘蛛 spider』去『爬crawl [krɔːl]』個網站並且提取數據
  3. 使用命令行去導出被剝的數據
  4. 改變蜘蛛去『遞歸 recursively』捉鏈接
  5. 使用蜘蛛入參

Creating a project

在你開始剝之前,你必須配置好一個「剝工程」。進入一個目錄,「個地放係 where」你中意攞去存你啲 code 嘅。

1
scrapy startproject tutorial

這個會創建一個 tutorial 目錄帶有下面的內容:

1
2
3
4
5
6
7
8
9
10
tutorial/
scrapy.cfg # 部署設定
tutorial/ # 工程模塊,你將會從此處入啲 code
__init__.py
items.py # 工程項目定義文件
middlewares.py # 中間件
pipelines.py # 流水線
settings.py # 設定
spiders/ # 個地方係放蜘蛛
__init__.py

Out first Spider

蜘蛛是多個類,你定義這些類,用去從網站剝些信息。必須定義這些初始請求,知道如何去跟蹤頁面的這些鏈接,同如何去解釋這些下載內容頁,提取出數據。

這些代碼就是我們的第一個蜘蛛啦。保存成 quotes_spider.py ,在 tutorial/spiders 目錄下,個目錄在你的工程目錄下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import scrapy

class QuotesSpider(scrapy.Spider):

# 運行命令: scrapy crawl quotes
name = "quotes"

def start_requests(self):
urls = [
'http://quotes.toscrape.com/page/1/',
'http://quotes.toscrape.com/page/2/',
]
for url in urls:
yield scrapy.Request(url=url, callback=self.parse)

def parse(self, response):
# ['http:', '', 'quotes.toscrape.com', 'page', '1', '']
page = response.url.split("/")[-2]

# quotes-1.html
# >>> str = "%s" % 123
# >>> str
# '123'
filename = 'quotes-%s.html' % page

with open(filename, 'wb') as f:
f.write(response.body)

# 2019-12-15 03:56:50 [quotes] DEBUG: Saved file quotes-1.html
self.log('Saved file %s' % filename)

如你所見,個蜘蛛的子類 scrapy.Spider 同個蜘蛛定義一些屬性同方法:

  • name : 識別蜘蛛。必須獨一無二。
  • start_requests() : 必須返回一個可重複的請求。意思係你能夠返回一列請求或者寫一個生成函數。個蜘蛛將會開始剝那些請求。
  • parse() : 一個方法用去調用去解決下載的回應,啲下載請求係每個請求生成。個 response 的參變量是 Textresponse 的實例。個實例有頁面內容同更多有有用嘅方法去調用。
    parse 方法通常用來解那些 response,提取那些剝出來的數據,生成「字典」。會找出新的那些url去跟蹤同創建新的請求。

How to run our spider

去到最頂層目錄,即是最頂的 tutorial ,運行:

1
scrapy crawl quotes

What just happened under the hood? 底層發生了什麼?

Scrapy 安排了個 scrapy.Request 對象,由 start_request 返回的。Upon 當 接收每個回應時候,會初始化 Response 對象,並且調用 callback 去關連 parse 方法,response 會作爲 parse 方法的入參。

A shortcut to the start_requests method 簡便方法去達到 start_requests 方法

不做 start_requests() 方法,雖然方法會從 url 生成 scrapy.Request 對。你可以定義 start_urls帶有 attribute with 一列 url。個列表會給 start_requests() 來用,創建初始化請求。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import scrapy

class QuotesSpider(scrapy.Spider):
name = "quotes"
start_urls = [
'http://quotes.toscrape.com/page/1/',
'http://quotes.toscrape.com/page/2/',
]

def parse(self, response):
page = response.url.split("/")[-2]
filename = 'quotes-%s.html' % page
with open(filename, 'wb') as f:
f.write(response.body)
self.log('Saved file %s' % filename)

即使我們沒有直接去告訴Scrapy去做,但係個 parse() 方法將會拿來解決每個請求,urls那些請求。之所以會這樣,因爲 parse() 是 Scrapy 的默認回調方法,parse() 會被人調用,儘管沒有 call 佢。

Extracting data