為什么使用Scrapy载绿?
我們可以用requests和beautifulsoup完成一個(gè)實(shí)用的爬蟲唉侄,但如果想大規(guī)模爬取的話育勺,我們需要學(xué)習(xí)Scrapy這個(gè)優(yōu)秀Python框架,學(xué)習(xí)它的哲學(xué)思想早芭,可以幫助我們更好寫自己的爬蟲彼城。
事前準(zhǔn)備
由于Windows存在許多莫名其妙的坑,所以建議安裝anaconda這個(gè)優(yōu)秀的python發(fā)行版退个,并且在anaconda目錄添加到環(huán)境變量中募壕。
- 使用<code>create -n scrapy_app python=2 scrapy</code>創(chuàng)建一個(gè)預(yù)裝scrapy的虛擬環(huán)境。
- 在cmd下啟動(dòng)虛擬環(huán)境<code> activate scrapy_app</code>语盈。
- <code>conda install -c scrapinghub scrapy</code>安裝其他必須庫
- <code>scrapy bench </code>驗(yàn)證能否正常工作
官方教程
1.新建項(xiàng)目<code>scrapy startproject tutorial</code>
這個(gè)命令將會(huì)創(chuàng)建如下內(nèi)容:
2.定義Item
items用來裝scraped data司抱,也就是從網(wǎng)頁提取的數(shù)據(jù),是一類簡單的Python字典黎烈。比如我們想從stackoverflow提取問題名习柠、鏈接和描述。那么就可以在items.py做如下定義照棋。
import scrapy
class DmozItem(scrapy.Item):
# define the fields for your item here like:
# name = scrapy.Field()
title = scrapy.Field()
link = scrapy.Field()
desc = scrapy.Field()
3.第一個(gè)爬蟲(spider)
爬蟲是你自定義的類资溃,用于讓Scrapy從某個(gè)網(wǎng)站提取信息。你需要定義起始的URL(start_urls)烈炭,如何跟蹤鏈接以及如何檢索網(wǎng)頁內(nèi)容并進(jìn)行提取溶锭。
我們可以在命令行中輸入<code>scrapy genspider -t basic domz dmoz.org</code>創(chuàng)建一個(gè)爬蟲,得到spiders/domz.py符隙。
# -- coding: utf-8 --
import scrapy
class DomzSpider(scrapy.Spider):
name = "domz" #用于定位爬蟲
allowed_domains = ["dmoz.org"] #限定域名趴捅,就不會(huì)爬到baidu.com了
start_urls =[
"http://www.dmoz.org/Computers/Programming/Languages/Python/Books/",
"http://www.dmoz.org/Computers/Programming/Languages/Python/Resources/"
] # 起始的URL
def parse(self, response):
filename = response.url.split("/")[-2]+'.html'
with open(filename,'wb') as f:
f.write(response.body)
# parse是Scarpy在請求未指定回調(diào)時(shí),用于處理下載響應(yīng)的默認(rèn)回調(diào)霹疫。
進(jìn)一步想了解scrapy.Spider的話看這里拱绑。
4.工作吧!爬蟲
命令行下輸入<code>scrapy crawl domz</code>丽蝎。
結(jié)束后會(huì)在項(xiàng)目文件下載生成兩個(gè)HTML文件猎拨。單單下載網(wǎng)頁并沒有意義,我們需要從網(wǎng)頁從提取數(shù)據(jù)才有意義。
5.數(shù)據(jù)提取
Scrapy使用基于Xpath或CSS表達(dá)式的Scrapy Selectors提取網(wǎng)頁數(shù)據(jù)红省。
讓我們在shell下使用一下Scrapy Selectors吧额各。<code>scrapy shell "http://www.dmoz.org/Computers/Programming/Languages/Python/Books/"</code>
In [1]: response.xpath('//title')
Out[1]: [<Selector xpath='//title' data=u'<title>Open Directory - Computers: Progr'>]
In [2]: response.xpath('//title').extract()
Out[2]: [u'<title>Open Directory - Computers: Programming: Languages: Python: Books</title>']
In [3]: response.xpath('//title/text()')
Out[3]: [<Selector xpath='//title/text()' data=u'Open Directory - Computers: Programming:'>]
In [4]: response.xpath('//title/text()').extract()
Out[4]: [u'Open Directory - Computers: Programming: Languages: Python: Books']
In [5]: response.xpath('//title/text()').re('(\w+):')
Out[5]: [u'Computers', u'Programming', u'Languages', u'Python']
因此,我們可以改寫之前dmoz.py中的parse部分吧恃。
.......
def parse(self, response):
for sel in response.xpath('//ui/li'):
title = sel.xpath('a/text()').extract()
link = sel.xpath('a/@href').extract()
desc = sel.xpath('text()').extract()
print title, link, desc
重新運(yùn)行<code>scrapy crawl domz</code>
這里我們只是把結(jié)果打印出來虾啦,實(shí)際運(yùn)行應(yīng)該是把數(shù)據(jù)保存下來,首先需要用到之前定義的DmozItem先結(jié)構(gòu)化數(shù)據(jù)痕寓, 繼續(xù)改寫傲醉。
from tutorial.items import DmozItem
...
def parse(self, response):
for sel in response.xpath('//ui/li'):
item = DmozItem()
item['title']' = sel.xpath('a/text()').extract()
item['link'] = sel.xpath('a/@href').extract()
item['desc'] = sel.xpath('text()').extract()
yield item
重新運(yùn)行<code>scrapy crawl domz</code>
6.鏈接跟蹤
假設(shè)你不滿足爬取起始頁面,想繼續(xù)爬取起始頁面中你感興趣的鏈接厂抽,那么我么就需要進(jìn)一步改寫之前的爬蟲了。
def parse(self, response):
for href in response.css("ul.directory.dir-col > li > a::attr('href')"):
url = response.urljoin(href.extract())#構(gòu)建絕對路徑的URL
yield scrapy.Request(url, callback=self.parse_dir_contents)
def parse_dir_contents(self, response):
for sel in response.xpath('//ui/li'):
item = DmozItem()
item['title']' = sel.xpath('a/text()').extract()
item['link'] = sel.xpath('a/@href').extract()
item['desc'] = sel.xpath('text()').extract()
yield item
這里我們使用parse函數(shù)獲取網(wǎng)頁的url丁眼,然后通過scrapy.Request對獲取的每一個(gè)url調(diào)用parse_dir_contents函數(shù)筷凤,提取數(shù)據(jù)。
7.數(shù)據(jù)儲(chǔ)存
數(shù)據(jù)儲(chǔ)存有很多方式苞七,可以放在數(shù)據(jù)庫中藐守,由于是教程,我們使用最簡單的<code>scrapy crawl domz -o items.json</code>把數(shù)據(jù)放在json文件中蹂风。