内容都是從官方文檔整理過來的,隻整理一部分,要想深入了解,可以看官方文檔
一窺示例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項目。 進入您打算存儲代碼的目錄中,運作下列指令:
該指令将會建立包含下列内容的 <code>tutorial</code> 目錄:
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:
在項目的跟目錄下多了兩個html檔案
繼續在項目的根目錄下運作 :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><head></code> 标簽内的 <code><title></code> 元素
<code>/html/head/title/text()</code>:
選擇上面提到的 <code><title></code> 元素的文字
<code>//td</code>:
選擇所有的 <code><td></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>&</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.