注解
本教程所使用的樣例站 Google Directory 已經(jīng)被 Google 關(guān)閉了。不過(guò)教程中的概念任然適用。 如果您打算使用一個(gè)新的網(wǎng)站來(lái)更新本教程,您的貢獻(xiàn)是再歡迎不過(guò)了。 詳細(xì)信息請(qǐng)參考 Contributing to Scrapy。
本文檔介紹了如何適用 Firebug(一個(gè) Firefox 的插件)來(lái)使得爬取更為簡(jiǎn)單,有趣。更多有意思的 Firefox 插件請(qǐng)參考對(duì)爬取有幫助的實(shí)用 Firefox 插件。使用 Firefox 插件檢查頁(yè)面需要有些注意事項(xiàng):在瀏覽器中檢查 DOM 的注意事項(xiàng)
。
在本樣例中將展現(xiàn)如何使用 Firebug 從 Google Directory 來(lái)爬取數(shù)據(jù)。Google Directory 包含了入門(mén)教程
里所使用的 Open Directory Project 中一樣的數(shù)據(jù),不過(guò)有著不同的結(jié)構(gòu)。
Firebug 提供了非常實(shí)用的檢查元素
功能。該功能允許您將鼠標(biāo)懸浮在不同的頁(yè)面元素上, 顯示相應(yīng)元素的 HTML 代碼。否則,您只能十分痛苦的在 HTML 的 body 中手動(dòng)搜索標(biāo)簽。
在下列截圖中,您將看到 檢查元素 的執(zhí)行效果。
http://wiki.jikexueyuan.com/project/scrapy/images/1.png" alt="" />
首先我們能看到目錄根據(jù)種類(lèi)進(jìn)行分類(lèi)的同時(shí),還劃分了子類(lèi)。
不過(guò),看起來(lái)子類(lèi)還有更多的子類(lèi),而不僅僅是頁(yè)面顯示的這些,所以我們接著查找:
http://wiki.jikexueyuan.com/project/scrapy/images/2.png" alt="" />
正如路徑的概念那樣,子類(lèi)包含了其他子類(lèi)的鏈接,同時(shí)也鏈接到實(shí)際的網(wǎng)站中。
查看路徑的 URL,我們可以看到 URL 的通用模式(pattern):
http://directory.google.com/Category/Subcategory/Another_Subcategory
了解到這個(gè)消息,我們可以構(gòu)建一個(gè)跟進(jìn)的鏈接的正則表達(dá)式:
directory\.google\.com/[A-Z][a-zA-Z_/]+$
因此,根據(jù)這個(gè)表達(dá)式,我們創(chuàng)建第一個(gè)爬取規(guī)則:
Rule(LinkExtractor(allow='directory.google.com/[A-Z][a-zA-Z_/]+$', ),
'parse_category',
follow=True,
),
Rule
對(duì)象指導(dǎo)基于 CrawlSpider
的 spider 如何跟進(jìn)目錄鏈接。 parse_category 是 spider 的方法,用于從頁(yè)面中處理也提取數(shù)據(jù)。
spider 的代碼如下:
from scrapy.contrib.linkextractors import LinkExtractor
from scrapy.contrib.spiders import CrawlSpider, Rule
class GoogleDirectorySpider(CrawlSpider):
name = 'directory.google.com'
allowed_domains = ['directory.google.com']
start_urls = ['http://directory.google.com/']
rules = (
Rule(LinkExtractor(allow='directory\.google\.com/[A-Z][a-zA-Z_/]+$'),
'parse_category', follow=True,
),
)
def parse_category(self, response):
# write the category page data extraction code here
pass
現(xiàn)在我們來(lái)編寫(xiě)提取數(shù)據(jù)的代碼。
在 Firebug 的幫助下,我們將查看一些包含網(wǎng)站鏈接的網(wǎng)頁(yè)(以 http://directory.google.com/Top/Arts/Awards/為例),找到使用 Selectors 提取鏈接的方法。我們也將使用 Scrapy shell
來(lái)測(cè)試得到的 XPath
表達(dá)式,確保表達(dá)式工作符合預(yù)期。
http://wiki.jikexueyuan.com/project/scrapy/images/3.png" alt="" />
正如您所看到的那樣,頁(yè)面的標(biāo)記并不是十分明顯: 元素并不包含 id
,class
或任何可以區(qū)分的屬性。所以我們將使用等級(jí)槽(rank bar)作為指示點(diǎn)來(lái)選擇提取的數(shù)據(jù),創(chuàng)建 XPath。
使用 Firebug,我們可以看到每個(gè)鏈接都在 td
標(biāo)簽中。該標(biāo)簽存在于同時(shí)(在另一個(gè) td
)包含鏈接的等級(jí)槽(ranking bar)的 tr
中。
所以我們選擇等級(jí)槽(ranking bar),接著找到其父節(jié)點(diǎn)(tr),最后是(包含我們要爬取數(shù)據(jù)的)鏈接的 td 。
對(duì)應(yīng)的 XPath:
//td[descendant::a[contains(@href, "#pagerank")]]/following-sibling::td//a
使用 Scrapy 終端
來(lái)測(cè)試這些復(fù)雜的 XPath 表達(dá)式,確保其工作符合預(yù)期。
簡(jiǎn)單來(lái)說(shuō),該表達(dá)式會(huì)查找等級(jí)槽的 td
元素,接著選擇所有 td
元素,該元素?fù)碛凶訉O a
元素,且 a
元素的屬性 href
包含字符串 #pagerank
。
當(dāng)然,這不是唯一的 XPath,也許也不是選擇數(shù)據(jù)的最簡(jiǎn)單的那個(gè)。 其他的方法也可能是,例如,選擇灰色的鏈接的 font
標(biāo)簽。
最終,我們編寫(xiě) parse_category()
方法:
def parse_category(self, response):
# The path to website links in directory page
links = response.xpath('//td[descendant::a[contains(@href, "#pagerank")]]/following-sibling::td/font')
for link in links:
item = DirectoryItem()
item['name'] = link.xpath('a/text()').extract()
item['url'] = link.xpath('a/@href').extract()
item['description'] = link.xpath('font[2]/text()').extract()
yield item
注意,您可能會(huì)遇到有些在 Firebug 找到,但是在原始 HTML 中找不到的元素, 例如典型的 <tbody>
元素, 或者 Firebug 檢查活動(dòng) DOM(live DOM)所看到的元素,但元素由 javascript 動(dòng)態(tài)生成,并不在 HTML 源碼中。 (原文語(yǔ)句亂了,上面為意譯- -: or tags which Therefer in page HTML sources may on Firebug inspects the live DOM )。