Scrapy Shell¶
Scrapy Shell 是一個互動式的 Shell,您可以在其中快速嘗試和除錯您的抓取程式碼,而無需執行爬蟲。它主要用於測試資料提取程式碼,但您實際上也可以將它用於測試任何類型的程式碼,因為它也是一個常規的 Python Shell。
此 Shell 用於測試 XPath 或 CSS 表達式,並查看它們如何運作以及它們從您嘗試抓取的網頁中提取哪些資料。它允許您在編寫爬蟲時互動式地測試您的表達式,而無需執行爬蟲來測試每個變更。
一旦您熟悉 Scrapy Shell,您就會發現它是開發和除錯您的爬蟲的寶貴工具。
設定 Shell¶
如果您已安裝 IPython,Scrapy Shell 將會使用它(而不是標準的 Python 控制台)。IPython 控制台功能更強大,除了其他功能外,還提供智慧自動完成和彩色輸出。
我們強烈建議您安裝 IPython,特別是如果您在 Unix 系統上工作(IPython 在此系統中表現出色)。有關更多資訊,請參閱 IPython 安裝指南。
Scrapy 也支援 bpython,並且會在 IPython 無法使用時嘗試使用它。
透過 Scrapy 的設定,您可以將其設定為使用 ipython
、bpython
或標準 python
Shell 中的任何一個,無論安裝了哪個。這可以透過設定 SCRAPY_PYTHON_SHELL
環境變數來完成;或在您的 scrapy.cfg 中定義它
[settings]
shell = bpython
啟動 Shell¶
要啟動 Scrapy Shell,您可以使用 shell
命令,如下所示
scrapy shell <url>
其中 <url>
是您想要抓取的 URL。
shell
也適用於本機檔案。如果您想要使用網頁的本機副本,這可能會很方便。shell
了解本機檔案的以下語法
# UNIX-style
scrapy shell ./path/to/file.html
scrapy shell ../other/path/to/file.html
scrapy shell /absolute/path/to/file.html
# File URI
scrapy shell file:///absolute/path/to/file.html
注意
使用相對檔案路徑時,請明確使用 ./
(或在相關時使用 ../
) 作為前綴。scrapy shell index.html
將無法如預期般運作(這是設計使然,而不是錯誤)。
因為 shell
偏好 HTTP URL 勝於檔案 URI,而且 index.html
在語法上與 example.com
相似,shell
會將 index.html
視為網域名稱並觸發 DNS 查詢錯誤
$ scrapy shell index.html
[ ... scrapy shell starts ... ]
[ ... traceback ... ]
twisted.internet.error.DNSLookupError: DNS lookup failed:
address 'index.html' not found: [Errno -5] No address associated with hostname.
shell
不會事先測試目前的目錄中是否存在名為 index.html
的檔案。再次強調,請明確指定。
使用 Shell¶
Scrapy Shell 只是一個常規的 Python 控制台 (如果您有可用的 IPython 控制台),它為了方便起見提供了一些額外的快捷功能。
可用的快捷鍵¶
shelp()
- 列印包含可用物件和快捷鍵清單的說明fetch(url[, redirect=True])
- 從給定的 URL 擷取新的回應,並相應地更新所有相關物件。您可以選擇透過傳遞redirect=False
來要求不要追蹤 HTTP 3xx 重新導向fetch(request)
- 從給定的請求擷取新的回應,並相應地更新所有相關物件。view(response)
- 在您本機的網頁瀏覽器中開啟給定的回應以進行檢查。這會將 <base> 標籤 新增至回應主體,以便外部連結 (例如圖片和樣式表) 能夠正確顯示。但是請注意,這會在您的電腦中建立一個臨時檔案,該檔案不會自動移除。
可用的 Scrapy 物件¶
Scrapy Shell 會自動從下載的頁面建立一些方便的物件,例如 Response
物件和 Selector
物件 (針對 HTML 和 XML 內容)。
這些物件是
Shell 會話範例¶
以下是一個典型的 Shell 會話範例,我們首先抓取 https://scrapy.org 頁面,然後繼續抓取 https://old.reddit.com/ 頁面。最後,我們將 (Reddit) 請求方法修改為 POST 並重新擷取它,以獲得錯誤。我們透過輸入 Ctrl-D (在 Unix 系統中) 或 Ctrl-Z (在 Windows 中) 來結束會話。
請記住,您嘗試執行時,這裡提取的資料可能不會相同,因為這些頁面不是靜態的,並且在您測試時可能已經變更。此範例的唯一目的是讓您熟悉 Scrapy Shell 的運作方式。
首先,我們啟動 shell
scrapy shell 'https://scrapy.org' --nolog
注意
請記住,當從命令行執行 Scrapy shell 時,請務必將 URL 用引號括起來,否則包含參數的 URL(即包含 &
字元的 URL)將無法正常運作。
在 Windows 上,請改用雙引號。
scrapy shell "https://scrapy.org" --nolog
接著,shell 會擷取 URL(使用 Scrapy 下載器),並印出可用的物件列表和有用的快捷鍵(您會注意到這些行都以 [s]
前綴開頭)。
[s] Available Scrapy objects:
[s] scrapy scrapy module (contains scrapy.Request, scrapy.Selector, etc)
[s] crawler <scrapy.crawler.Crawler object at 0x7f07395dd690>
[s] item {}
[s] request <GET https://scrapy.org>
[s] response <200 https://scrapy.org/>
[s] settings <scrapy.settings.Settings object at 0x7f07395dd710>
[s] spider <DefaultSpider 'default' at 0x7f0735891690>
[s] Useful shortcuts:
[s] fetch(url[, redirect=True]) Fetch URL and update local objects (by default, redirects are followed)
[s] fetch(req) Fetch a scrapy.Request and update local objects
[s] shelp() Shell help (print this help)
[s] view(response) View response in a browser
>>>
在那之後,我們就可以開始玩弄這些物件了。
>>> response.xpath("//title/text()").get()
'Scrapy | A Fast and Powerful Scraping and Web Crawling Framework'
>>> fetch("https://old.reddit.com/")
>>> response.xpath("//title/text()").get()
'reddit: the front page of the internet'
>>> request = request.replace(method="POST")
>>> fetch(request)
>>> response.status
404
>>> from pprint import pprint
>>> pprint(response.headers)
{'Accept-Ranges': ['bytes'],
'Cache-Control': ['max-age=0, must-revalidate'],
'Content-Type': ['text/html; charset=UTF-8'],
'Date': ['Thu, 08 Dec 2016 16:21:19 GMT'],
'Server': ['snooserv'],
'Set-Cookie': ['loid=KqNLou0V9SKMX4qb4n; Domain=reddit.com; Max-Age=63071999; Path=/; expires=Sat, 08-Dec-2018 16:21:19 GMT; secure',
'loidcreated=2016-12-08T16%3A21%3A19.445Z; Domain=reddit.com; Max-Age=63071999; Path=/; expires=Sat, 08-Dec-2018 16:21:19 GMT; secure',
'loid=vi0ZVe4NkxNWdlH7r7; Domain=reddit.com; Max-Age=63071999; Path=/; expires=Sat, 08-Dec-2018 16:21:19 GMT; secure',
'loidcreated=2016-12-08T16%3A21%3A19.459Z; Domain=reddit.com; Max-Age=63071999; Path=/; expires=Sat, 08-Dec-2018 16:21:19 GMT; secure'],
'Vary': ['accept-encoding'],
'Via': ['1.1 varnish'],
'X-Cache': ['MISS'],
'X-Cache-Hits': ['0'],
'X-Content-Type-Options': ['nosniff'],
'X-Frame-Options': ['SAMEORIGIN'],
'X-Moose': ['majestic'],
'X-Served-By': ['cache-cdg8730-CDG'],
'X-Timer': ['S1481214079.394283,VS0,VE159'],
'X-Ua-Compatible': ['IE=edge'],
'X-Xss-Protection': ['1; mode=block']}
從爬蟲中調用 shell 來檢查響應¶
有時您會想要檢查爬蟲中特定點正在處理的響應,哪怕只是為了確認您預期的響應到達了。
這可以透過使用 scrapy.shell.inspect_response
函式來達成。
以下是如何從您的爬蟲中調用它的範例。
import scrapy
class MySpider(scrapy.Spider):
name = "myspider"
start_urls = [
"http://example.com",
"http://example.org",
"http://example.net",
]
def parse(self, response):
# We want to inspect one specific response.
if ".org" in response.url:
from scrapy.shell import inspect_response
inspect_response(response, self)
# Rest of parsing code.
當您執行爬蟲時,您會看到類似以下的內容。
2014-01-23 17:48:31-0400 [scrapy.core.engine] DEBUG: Crawled (200) <GET http://example.com> (referer: None)
2014-01-23 17:48:31-0400 [scrapy.core.engine] DEBUG: Crawled (200) <GET http://example.org> (referer: None)
[s] Available Scrapy objects:
[s] crawler <scrapy.crawler.Crawler object at 0x1e16b50>
...
>>> response.url
'http://example.org'
然後,您可以檢查提取程式碼是否正常運作。
>>> response.xpath('//h1[@class="fn"]')
[]
不,它沒有。所以您可以開啟瀏覽器中的響應,看看它是否是您預期的響應。
>>> view(response)
True
最後,按下 Ctrl-D(在 Windows 上是 Ctrl-Z)退出 shell 並恢復爬取。
>>> ^D
2014-01-23 17:50:03-0400 [scrapy.core.engine] DEBUG: Crawled (200) <GET http://example.net> (referer: None)
...
請注意,您在這裡不能使用 fetch
快捷鍵,因為 Scrapy 引擎被 shell 阻塞了。然而,在您離開 shell 後,爬蟲將會從它停止的地方繼續爬取,如上所示。