Scrapy 是一個為了爬取網(wǎng)站數(shù)據(jù),提取結(jié)構(gòu)性數(shù)據(jù)而編寫的應(yīng)用框架。 可以應(yīng)用在包括數(shù)據(jù)挖掘,信息處理或存儲歷史數(shù)據(jù)等一系列的程序中。
其最初是為了頁面抓取 (更確切來說,網(wǎng)絡(luò)抓取)所設(shè)計(jì)的, 也可以應(yīng)用在獲取 API 所返回的數(shù)據(jù)(例如 Amazon Associates Web Services ) 或者通用的網(wǎng)絡(luò)爬蟲。
本文檔將通過介紹 Scrapy 背后的概念使您對其工作原理有所了解, 并確定Scrapy是否是您所需要的。
當(dāng)您準(zhǔn)備好開始您的項(xiàng)目后,您可以參考入門教程。
當(dāng)您需要從某個網(wǎng)站中獲取信息,但該網(wǎng)站未提供API或能通過程序獲取信息的機(jī)制時,Scrapy 可以助你一臂之力。
以 Mininova 網(wǎng)站為例,我們想要獲取今日添加的所有種子的 URL、名字、描述以及文件大小信息。
今日添加的種子列表可以通過這個頁面找到:
http://www.mininova.org/today
第一步是定義我們需要爬取的數(shù)據(jù)。在 Scrapy 中, 這是通過 Scrapy Items 來完成的。(在本例子中為種子文件)
我們定義的 Item:
import scrapy
class TorrentItem(scrapy.Item):
url = scrapy.Field()
name = scrapy.Field()
description = scrapy.Field()
size = scrapy.Field()
第二步是編寫一個 spider。其定義了初始 URL(http://www.mininova.org/today)、針對后續(xù)鏈接的規(guī)則以及從頁面中提取數(shù)據(jù)的規(guī)則。
通過觀察頁面的內(nèi)容可以發(fā)現(xiàn),所有種子的 URL 都類似 http://www.mininova.org/tor/NUMBER
。 其中,NUMBER
是一個整數(shù)。 根據(jù)此規(guī)律,我們可以定義需要進(jìn)行跟進(jìn)的鏈接的正則表達(dá)式: /tor/\d+
。
我們使用 XPath 來從頁面的HTML源碼中選擇需要提取的數(shù)據(jù)。 以其中一個種子文件的頁面為例:
http://www.mininova.org/tor/2676093
觀察 HTML 頁面源碼并創(chuàng)建我們需要的數(shù)據(jù)(種子名字,描述和大小)的 XPath 表達(dá)式。
通過觀察,我們可以發(fā)現(xiàn)文件名是包含在 <h1>
標(biāo)簽中的:
<h1>Darwin - The Evolution Of An Exhibition</h1>
與此對應(yīng)的 XPath 表達(dá)式:
//h1/text()
種子的描述是被包含在 id="description"
的<div>
標(biāo)簽中:
<h2>Description:</h2>
<div id="description">
Short documentary made for Plymouth City Museum and Art Gallery regarding the setup of an exhibit about Charles Darwin in conjunction with the 200th anniversary of his birth.
...
對應(yīng)獲取描述的 XPath 表達(dá)式:
//div[@id='description']
文件大小的信息包含在 id=specifications
的<div>
的第二個<p>
標(biāo)簽中:
<div id="specifications">
<p>
<strong>Category:</strong>
<a href="/cat/4">Movies</a> > <a href="/sub/35">Documentary</a>
</p>
<p>
<strong>Total size:</strong>
150.62 megabyte</p>
選擇文件大小的 XPath 表達(dá)式:
//div[@id='specifications']/p[2]/text()[2]
關(guān)于 XPath 的詳細(xì)內(nèi)容請參考 XPath 參考 。
最后,結(jié)合以上內(nèi)容給出 spider 的代碼:
from scrapy.contrib.spiders import CrawlSpider, Rule
from scrapy.contrib.linkextractors import LinkExtractor
class MininovaSpider(CrawlSpider):
name = 'mininova'
allowed_domains = ['mininova.org']
start_urls = ['http://www.mininova.org/today']
rules = [Rule(LinkExtractor(allow=['/tor/\d+']), 'parse_torrent')]
def parse_torrent(self, response):
torrent = TorrentItem()
torrent['url'] = response.url
torrent['name'] = response.xpath("http://h1/text()").extract()
torrent['description'] = response.xpath("http://div[@id='description']").extract()
torrent['size'] = response.xpath("http://div[@id='info-left']/p[2]/text()[2]").extract()
return torrent
TorrentItem
的定義在 上面 。
終于,我們可以運(yùn)行 spider 來獲取網(wǎng)站的數(shù)據(jù),并以 JSON 格式存入到 scraped_data.json 文件中:
scrapy crawl mininova -o scraped_data.json
命令中使用了 Feed 導(dǎo)出 來導(dǎo)出 JSON 文件。您可以修改導(dǎo)出格式(XML 或者 CSV)或者存儲后端(FTP 或者 Amazon S3),這并不困難。
同時,您也可以編寫 item 管道 將 item 存儲到數(shù)據(jù)庫中。
執(zhí)行結(jié)束后,當(dāng)您查看 scraped_data.json
,您將看到提取到的 item:
[{"url": "http://www.mininova.org/tor/2676093", "name": ["Darwin - The Evolution Of An Exhibition"], "description": ["Short documentary made for Plymouth ..."], "size": ["150.62 megabyte"]},
# ... other items ...
]
由于 選擇器(Selectors) 返回 list,所以值都是以 list 存儲的(除了 url
是直接賦值之外)。 如果您想要保存單個數(shù)據(jù)或者對數(shù)據(jù)執(zhí)行額外的處理,那將是 Item Loaders 發(fā)揮作用的地方。
您已經(jīng)了解了如何通過 Scrapy 提取存儲網(wǎng)頁中的信息,但這僅僅只是冰山一角。Scrapy 提供了很多強(qiáng)大的特性來使得爬取更為簡單高效,例如:
下一步當(dāng)然是 下載 Scrapy 了, 您可以閱讀Scrapy 入門教程并加入社區(qū)。感謝您的支持!