我們已經(jīng)成功得到了title翁锡,但是再仔細(xì)看看阱洪,還能發(fā)現(xiàn)更簡(jiǎn)便的方法李根。
Gumtree為標(biāo)簽添加了屬性缓苛,就是itemprop=name校摩。所以XPath可以簡(jiǎn)化為//*[@itemprop="name"][1]/text()看峻。在XPath中,切記數(shù)組是從1開始的衙吩,所以這里[]里面是1互妓。
選擇itemprop="name"這個(gè)屬性,是因?yàn)镚umtree用這個(gè)屬性命名了許多其他的內(nèi)容坤塞,比如“You may also like”冯勉,用數(shù)組序號(hào)提取會(huì)很方便。
接下來(lái)看價(jià)格摹芙。價(jià)格在HTML中的位置如下:
<strong class="ad-price txt-xlarge txt-emphasis" itemprop="price">£334.39pw</strong>
我們又看到了itemprop="name"這個(gè)屬性灼狰,XPath表達(dá)式為//*[@itemprop="price"][1]/text()。驗(yàn)證一下:
>>> response.xpath('//*[@itemprop="price"][1]/text()').extract()[u'\xa3334.39pw']
注意Unicode字符(£符號(hào))和價(jià)格350.00pw浮禾。這說(shuō)明要對(duì)數(shù)據(jù)進(jìn)行清理交胚。在這個(gè)例子中,我們用正則表達(dá)式提取數(shù)字和小數(shù)點(diǎn)盈电。使用正則方法如下:
>>> response.xpath('//*[@itemprop="price"][1]/text()').re('[.0-9]+')[u'334.39']
假如這就是我們要提取的所有信息蝴簇,整理如下:
目標(biāo)XPath表達(dá)式
title//*[@itemprop="name"][1]/text()
Example value: [u'set unique family well']
Price//*[@itemprop="price"][1]/text()
Example value (using re()):[u'334.39']
description//*[@itemprop="description"][1]/text()
Example value: [u'website court warehouse\r\npool...']
Address//*[@itemtype="http://schema.org/Place"][1]/text()
Example value: [u'Angel, London']
Image_URL//*[@itemprop="image"][1]/@src
Example value: [u'../images/i01.jpg']
這是我們的第一段代碼,要注意Python中是使用空格縮進(jìn)的挣轨。每個(gè)字段名之前都有四個(gè)空格或是一個(gè)tab军熏。如果一行有四個(gè)空格,另一行有三個(gè)空格卷扮,就會(huì)報(bào)語(yǔ)法錯(cuò)誤荡澎。如果一行是四個(gè)空格均践,另一行是一個(gè)tab,也會(huì)報(bào)錯(cuò)摩幔⊥空格符指定了這些項(xiàng)目是在PropertiesItem下面的。其他語(yǔ)言有的用花括號(hào){}或衡,有的用begin – end焦影,Python則使用空格。
import scrapy?
class BasicSpider(scrapy.Spider):
? ? name ="basic"
? ? allowed_domains = ["web"]
? ? ?start_URL = (
'http://www.web/',?
?)
def parse(self, response):
? ? ?pass
import命令可以讓我們使用Scrapy框架封断。然后定義了一個(gè)類BasicSpider斯辰,繼承自scrapy.Spider。繼承的意思是坡疼,雖然我們沒(méi)寫任何代碼彬呻,這個(gè)類已經(jīng)繼承了Scrapy框架中的類Spider的許多特性。這允許我們只需寫幾行代碼柄瑰,就可以有一個(gè)功能完整的爬蟲闸氮。然后我們看到了一些爬蟲的參數(shù),比如名字和抓取域字段名教沾。最后蒲跨,我們定義了一個(gè)空函數(shù)parse(),它有兩個(gè)參數(shù)self和response授翻。通過(guò)self或悲,可以使用爬蟲一些有趣的功能。response看起來(lái)很熟悉藏姐,它就是我們?cè)赟crapy shell中見(jiàn)到的響應(yīng)隆箩。
這是從這個(gè)頁(yè)面抓取的PropertiesItem。這很好羔杨,因?yàn)镾crapy就是圍繞Items的概念構(gòu)建的,這意味著我們可以用pipelines填充豐富項(xiàng)目杨蛋,或是用“Feed export”導(dǎo)出保存到不同的格式和位置兜材。
保存到文件
試運(yùn)行下面:
不用我們寫任何代碼,我們就可以用這些格式進(jìn)行存儲(chǔ)逞力。Scrapy可以自動(dòng)識(shí)別輸出文件的后綴名曙寡,并進(jìn)行輸出。這段代碼中涵蓋了一些常用的格式寇荧。CSV和XML文件很流行举庶,因?yàn)榭梢员籈xcel直接打開。JSON文件很流行是因?yàn)樗拈_放性和與JavaScript的密切關(guān)系揩抡。JSON和JSON Line格式的區(qū)別是.json文件是在一個(gè)大數(shù)組中存儲(chǔ)JSON對(duì)象户侥。這意味著如果你有一個(gè)1GB的文件镀琉,你可能必須現(xiàn)在內(nèi)存中存儲(chǔ),然后才能傳給解析器蕊唐。相對(duì)的屋摔,.jl文件每行都有一個(gè)JSON對(duì)象,所以讀取效率更高替梨。
不在文件系統(tǒng)中存儲(chǔ)生成的文件也很麻煩钓试。利用下面例子的代碼,你可以讓Scrapy自動(dòng)上傳文件到FTP或亞馬遜的S3 bucket副瀑。
$ scrapy crawl basic -o"ftp://user:pass@ftp.scrapybook.com/items.json "
$ scrapy crawl basic -o"s3://aws_key:aws_secret@scrapybook/items.json"
注意弓熏,證書和URL必須按照主機(jī)和S3更新,才能順利運(yùn)行糠睡。
另一個(gè)要注意的是硝烂,如果你現(xiàn)在使用scrapy parse,它會(huì)向你顯示被抓取的項(xiàng)目和抓取中新的請(qǐng)求:
當(dāng)出現(xiàn)意外結(jié)果時(shí)铜幽,scrapy parse可以幫你進(jìn)行debug滞谢,你會(huì)更感嘆它的強(qiáng)大。
清洗——項(xiàng)目加載器和雜務(wù)字段
恭喜你除抛,你已經(jīng)創(chuàng)建成功一個(gè)簡(jiǎn)單爬蟲了狮杨!讓我們讓它看起來(lái)更專業(yè)些。
我們使用一個(gè)功能類到忽,ItemLoader橄教,以取代看起來(lái)雜亂的extract()和xpath()。我們的parse()進(jìn)行如下變化:
defparse(self, response):
l = ItemLoader(item=PropertiesItem(), response=response)? ??
l.add_xpath('title','//*[@itemprop="name"][1]/text()')? ??
l.add_xpath('price','.//*[@itemprop="price"]''[1]/text()', re='[,.0-9]+')? ??
l.add_xpath('description','//*[@itemprop="description"]''[1]/text()')? ??
l.add_xpath('address','//*[@itemtype=''"http://schema.org/Place"][1]/text()')? ?
l.add_xpath('image_URL','//*[@itemprop="image"][1]/@src')
returnl.load_item()
是不是看起來(lái)好多了喘漏?事實(shí)上护蝶,它可不是看起來(lái)漂亮那么簡(jiǎn)單。它指出了我們現(xiàn)在要干什么翩迈,并且后面的加載項(xiàng)很清晰持灰。這提高了代碼的可維護(hù)性和自文檔化。(自文檔化负饲,self-documenting堤魁,是說(shuō)代碼的可讀性高,可以像文檔文件一樣閱讀)