天天看點

scrapy 教程初窺Scrapy安裝指南Scrapy入門教程例子

内容都是從官方文檔整理過來的,隻整理一部分,要想深入了解,可以看官方文檔

一窺示例spider       

為了讓您了解scrapy提供了什麼功能,我們将提供一個scrapy spider的示例,并且以最簡單的方式啟動該spider。以下的代碼将跟進stackoverflow上具有投票數最多的連結,并且爬取其中的一些資料:

将上述代碼存入到某個檔案中,以類似于 <code>stackoverflow_spider.py</code> 命名,

當指令執行完後,您将會得到 <code>top-stackoverflow-questions.json</code> 檔案。

該檔案以json格式儲存了stackoverflow上獲得upvote最多的問題, 包含了标題、連結、upvote的數目、相關的tags以及以html格式儲存的問題内容, 看起來類似于這樣(為了更容易閱讀,對内容進行重新排版):

following the pagination:

将上述代碼存入到某個檔案中,以類似于 <code>quotes_spider.py</code> 命名,

剛剛發生了什麼?

當您運作 <code>scrapy runspider somefile.py</code> 指令時,scrapy嘗試從該檔案中查找spider的定義,并且在爬取引擎中運作它。

scrapy首先讀取定義在 <code>start_urls</code> 屬性中的url(在本示例中,就是stackoverflow的top

question頁面的url), 建立請求,并且将接收到的response作為參數調用預設的回調函數 <code>parse</code> ,來啟動爬取。

在回調函數 <code>parse</code> 中,我們使用css

selector來提取連結。接着,我們産生(yield)更多的請求, 注冊 <code>parse_question</code> 作為這些請求完成時的回調函數。

這意味着,scrapy并不需要等待一個請求(request)完成及處理,在此同時, 也發送其他請求或者做些其他事情。 這也意味着,當有些請求失敗或者處理過程中出現錯誤時,其他的請求也能繼續處理。

最終, <code>parse_question</code> 回調函數從每個頁面中爬取到問題(question)的資料并産生了一個dict,

scrapy收集并按照終端(command line)的要求将這些結果寫入到了json檔案中。

注解

還有什麼?

您已經了解了如何通過scrapy提取存儲網頁中的資訊,但這僅僅隻是冰山一角。scrapy提供了很多強大的特性來使得爬取更為簡單高效, 例如:

提供了css選擇器(selector)以及xpath表達式進行處理, 以及一些幫助函數(helper method)來使用正規表達式來提取資料.

為您測試css及xpath表達式,編寫和調試爬蟲提供了極大的友善

針對非英語語系中不标準或者錯誤的編碼聲明, 提供了自動檢測以及健壯的編碼支援。

内置的中間件及擴充為下列功能提供了支援: * cookies and session 處理 * http 壓縮 * http 認證 * http 緩存 * user-agent模拟 * robots.txt * 爬取深度限制 * 其他

pipeline、 帶緩存的dns解析器,以及更多的特性。

安裝scrapy

在本篇教程中,我們假定您已經安裝好scrapy。

本篇教程中将帶您完成下列任務:

建立一個scrapy項目

定義提取的item

在開始爬取之前,您必須建立一個新的scrapy項目。 進入您打算存儲代碼的目錄中,運作下列指令:

scrapy 教程初窺Scrapy安裝指南Scrapy入門教程例子

該指令将會建立包含下列内容的 <code>tutorial</code> 目錄:

scrapy 教程初窺Scrapy安裝指南Scrapy入門教程例子

item 是儲存爬取到的資料的容器;其使用方法和python字典類似。雖然您也可以在scrapy中直接使用dict,但是 item 提供了額外保護機制來避免拼寫錯誤導緻的未定義字段錯誤。

(如果不了解orm, 不用擔心,您會發現這個步驟非常簡單)

首先根據需要從dmoz.org擷取到的資料對item進行模組化。 我們需要從dmoz中擷取名字,url,以及網站的描述。 對此,在item中定義相應的字段。編輯 <code>tutorial</code> 目錄中的 <code>items.py</code> 檔案:

一開始這看起來可能有點複雜,但是通過定義item, 您可以很友善的使用scrapy的其他方法。而這些方法需要知道您的item的定義。

spider是使用者編寫用于從單個網站(或者一些網站)爬取資料的類。其包含了一個用于下載下傳的初始url,如何跟進網頁中的連結以及如何分析頁面中的内容,

且定義一些屬性:

用于差別spider。 該名字必須是唯一的,您不可以為不同的spider設定相同的名字。

包含了spider在啟動時進行爬取的url清單。 是以,第一個被擷取到的頁面将是其中之一。 後續的url則從初始的url擷取到的資料中提取。

must return an iterable of requests (you can return a list of requests or write a generator function) which the spider will begin to crawl from. subsequent requests will be generated successively from these initial requests.

以下為我們的第一個spider代碼,儲存在 <code>tutorial/spiders</code> 目錄下的 <code>dmoz_spider.py</code> 檔案中:

第二個spider代碼,儲存在 <code>tutorial/spiders</code> 目錄下的 <code>quotes_spider.py</code> 檔案中:

進入項目的根目錄,執行下列指令啟動spider:

scrapy 教程初窺Scrapy安裝指南Scrapy入門教程例子
scrapy 教程初窺Scrapy安裝指南Scrapy入門教程例子

在項目的跟目錄下多了兩個html檔案

scrapy 教程初窺Scrapy安裝指南Scrapy入門教程例子

繼續在項目的根目錄下運作 :scrapy crawl dmoz

關聯的 回調 函數,把每一個接收到response傳給回調函數處理

一個快捷的處理

create the initial requests for your spider:

scrapy’s default callback method, which is called for requests without an explicitly assigned callback.

selectors選擇器簡介

這裡給出xpath表達式的例子及對應的含義:

<code>/html/head/title</code>:

選擇html文檔中 <code>&lt;head&gt;</code> 标簽内的 <code>&lt;title&gt;</code> 元素

<code>/html/head/title/text()</code>:

選擇上面提到的 <code>&lt;title&gt;</code> 元素的文字

<code>//td</code>:

選擇所有的 <code>&lt;td&gt;</code> 元素

<code>//div[@class="mine"]</code>:

選擇所有具有 <code>class="mine"</code> 屬性的 <code>div</code> 元素

css vs xpath: 您可以僅僅使用css

selector來從網頁中 提取資料。不過, xpath提供了更強大的功能。其不僅僅能指明資料所在的路徑, 還能檢視資料: 比如,您可以這麼進行選擇: 包含文字 ‘next page’ 的連結 。

正因為如此,即使您已經了解如何使用 css selector, 我們仍推薦您使用xpath

傳入xpath表達式,傳回該表達式所對應的所有節點的selector list清單 。

傳入css表達式,傳回該表達式所對應的所有節點的selector list清單.

序列化該節點為unicode字元串并傳回list。

根據傳入的正規表達式對資料進行提取,傳回unicode字元串list清單。

在shell中嘗試selector選擇器

當您在終端運作scrapy時,請一定記得給url位址加上引号,否則包含參數的url(例如 <code>&amp;</code> 字元)會導緻scrapy運作失敗。

當shell載入後,您将得到一個包含response資料的本地 <code>response</code> 變量。輸入 <code>response.body</code> 将輸出response的包體,

輸出 <code>response.headers</code> 可以看到response的標頭。

#todo.. 更為重要的是, <code>response</code> 擁有一個 <code>selector</code> 屬性,

您可以通過使用 <code>response.selector.xpath()</code> 或 <code>response.selector.css()</code> 來對 <code>response</code> 進行查詢。

此外,scrapy也對 <code>response.selector.xpath()</code> 及 <code>response.selector.css()</code> 提供了一些快捷方式,

例如 <code>response.xpath()</code> 或 <code>response.css()</code> ,

同時,shell根據response提前初始化了變量 <code>sel</code> 。該selector根據response的類型自動選擇最合适的分析規則(xml

vs html)。

之前提到過,每個 <code>.xpath()</code> 調用傳回selector組成的list,是以我們可以拼接更多的 <code>.xpath()</code> 來進一步擷取某個節點。我們将在下邊使用這樣的特性:

在我們的spider中加入這段代碼:

使用item

您可以使用标準的字典文法來擷取到其每個字段的值。(字段即是我們之前用field指派的屬性):

為了将爬取的資料傳回,我們最終的代碼将是:

現在對dmoz.org進行爬取将會産生 <code>dmozitem</code> 對象:

提取資料

if you run this spider, it will output the extracted data with the log:

存儲資料

最簡單的是通過指令行:scrapycrawlquotes-oquotes.json

在類似本篇教程裡這樣小規模的項目中,這種存儲方式已經足夠。

不過如果您僅僅想要儲存item,您不需要實作任何的pipeline。

既然已經能從頁面上爬取資料了,為什麼不提取您感興趣的頁面的連結,追蹤他們, 讀取這些連結的資料呢?

下面是實作這個功能的改進版spider:

現在, parse() 僅僅從頁面中提取我們感興趣的連結,使用 response.urljoin 方法構造一個絕對路徑的url(頁面上的連結都是相對路徑的),

産生(yield)一個請求, 該請求使用 parse_dir_contents() 方法作為回調函數,

用于最終産生我們想要的資料.。

這裡展現的即是scrpay的追蹤連結的機制: 當您在回調函數中yield一個request後, scrpay将會排程,發送該請求,并且在該請求完成時,調用所注冊的回調函數。

基于此方法,您可以根據您所定義的跟進連結的規則,建立複雜的crawler,并且, 根據所通路的頁面,提取不同的資料.

一種常見的方法是,回調函數負責提取一些item,查找能跟進的頁面的連結, 并且使用相同的回調函數yield一個 request:

上述代碼将建立一個循環,跟進所有下一頁的連結,直到找不到為止 – 對于爬取部落格、論壇以及其他做了分頁的網站十分有效

當運作爬蟲時,可以使用 <code>-a</code> 選項,為爬蟲提供指令行參數:

設定的參數通過 spider 的 <code>__init__</code> 方法

來變成 的 spider attributes.

這個例子中, 提供給 <code>tag</code> 參數的值

可以通過 <code>self.tag</code> 調用。

如果傳遞 <code>tag=humor</code> 參數給

spider,就隻會通路url的 “humor” 标簽,

such as <code>http://quotes.toscrape.com/tag/humor</code>.

一個是使用 css selectors 另一個是使用 xpath expressions.