一,scrapy和scrapy-redis的區(qū)別?
????scrapy是一個(gè)爬蟲通用框架,但不支持分布式,scrapy-redis是為了更方便的實(shí)現(xiàn)scrapy分布式爬蟲,而提供了一些以redis為基礎(chǔ)的組件
二,為什么scrapy框架不支持分布式?
????因?yàn)閟crcapy中的調(diào)度對(duì)列不支持共享,而scrapy-redis中,可以共享該對(duì)列
三,scrapy-redis工作原理?
? ? ? ? 1,爬蟲程序把請(qǐng)求鏈接,發(fā)送給爬蟲引擎,
? ? ? ? 2,爬蟲引擎把請(qǐng)求鏈接傳遞到調(diào)度對(duì)列
? ? ? ? 3,調(diào)度sheduler會(huì)把鏈接存放到redis數(shù)據(jù)庫(kù)中
? ? ? ? 4,redis數(shù)據(jù)庫(kù)因?yàn)榫哂屑系男再|(zhì),對(duì)去重有更好的體現(xiàn),傳進(jìn)來(lái)的鏈接會(huì)生成一個(gè)指紋,? ?redis會(huì)把?傳進(jìn)來(lái)的鏈接進(jìn)行對(duì)比,相同的鏈接直接去重,把沒(méi)有的鏈接加入到對(duì)列中,然后把鏈接再傳遞到調(diào)度對(duì)列中。
? ? ????5,調(diào)度中的對(duì)列把鏈接發(fā)送到下載模塊
? ????? 6,下載模塊,下載好數(shù)據(jù)后,把數(shù)據(jù)及下載的鏈接發(fā)送到爬蟲程序
? ? ????7,爬蟲程序把數(shù)據(jù)及鏈接發(fā)送到redis數(shù)據(jù)庫(kù)(如果此時(shí)自定義管道,則會(huì)把數(shù)據(jù)存放到自定義的數(shù)據(jù)庫(kù)中)
? ????? 8.,可以從redis數(shù)據(jù)庫(kù)中把數(shù)據(jù)下載到本地
四,redis怎么去重的?
如果多臺(tái)機(jī)器不僅往請(qǐng)求隊(duì)列存,還同時(shí)從里面取,那么如何保證每臺(tái)機(jī)子請(qǐng)求和存儲(chǔ)的隊(duì)列是不重復(fù)的呢?
借助redis集合
redis提供集合數(shù)據(jù)結(jié)構(gòu),我們知道集合里面的元素是不重復(fù)的
首先,在redis中存儲(chǔ)每個(gè)request的指紋。
在向request隊(duì)列中加入request前首先驗(yàn)證這個(gè)request的指紋是否已經(jīng)加入到集合中。
如果已存在,則不添加requets到隊(duì)列,
如果不存在,則將request添加入隊(duì)列并將指紋加入集合。
五,分布式爬蟲架構(gòu)實(shí)際上就是:
由一臺(tái)主機(jī)維護(hù)所有的爬取隊(duì)列,每臺(tái)從機(jī)的sheduler共享該隊(duì)列,協(xié)同存儲(chǔ)與提取。
分布式爬蟲的多臺(tái)協(xié)作的關(guān)鍵是共享爬取隊(duì)列
六,隊(duì)列用什么維護(hù)呢?
推薦redis隊(duì)列
redis是非關(guān)系型數(shù)據(jù)庫(kù),用key-value形式存儲(chǔ),結(jié)構(gòu)靈活,他不像關(guān)系型數(shù)據(jù)庫(kù)必須要由一定的結(jié)構(gòu)才能存儲(chǔ)。
key-value可以是多種數(shù)據(jù),非常靈活。
另外,redis是內(nèi)存中的數(shù)據(jù)結(jié)構(gòu)存儲(chǔ)系統(tǒng),處理速度快,性能好。
提供了隊(duì)列,集合多種存儲(chǔ)結(jié)構(gòu),方便隊(duì)列維護(hù)和去重操作。
七,怎樣防止中斷?
在爬取的過(guò)程中,難免會(huì)有某臺(tái)機(jī)子卡掉了,這時(shí)怎么辦?
在每臺(tái)從機(jī)scrapy啟動(dòng)時(shí)都會(huì)首先判斷當(dāng)前redis request隊(duì)列是否為空。
如果不為空,則從隊(duì)列中取得下一個(gè)request執(zhí)行爬取。
如果為空,則重新開(kāi)始開(kāi)始爬取,第一臺(tái)從機(jī)執(zhí)行爬取想隊(duì)列中添加request。
怎樣實(shí)現(xiàn)該架構(gòu)?
要做到:
維護(hù)request隊(duì)列
對(duì)臺(tái)從機(jī)調(diào)度reuqest
設(shè)置去重
鏈接redis
已經(jīng)有了比較成熟的庫(kù)scrapy-redis
scrapy-redis庫(kù)實(shí)現(xiàn)了如上架構(gòu),改寫了scrapy的調(diào)度器,隊(duì)列等組件
利用它可以方便地實(shí)現(xiàn)scrapy分布式架構(gòu)
https://github.com/rolando/scrapy-redis
八,步驟及代碼
? ? ? ? 1,安裝redis
????????????啟動(dòng)redis服務(wù):redis-server
????????????啟用shell客戶端:redis-cli 可以輸入指令 (在這里面啟動(dòng)指令)
? ??? ??2,修改配置文件redis.conf
????????把bind:127.0.0.1注釋掉,可以讓其他IP也可以訪問(wèn),其他爬蟲端才能連接到服務(wù)端的數(shù)據(jù)庫(kù)
? ??? ??3,連接到服務(wù)端測(cè)試
????????linux下? sudo redis-cli -h 服務(wù)端的IP? -h指定
????????如果-h沒(méi)有指定,就會(huì)默認(rèn)在本地
????????slave端無(wú)需啟動(dòng)radis-server,mster端啟動(dòng)即可,只要slave能讀取到mster中的數(shù)據(jù)庫(kù)就行了
????????代表可以實(shí)施分布式
? ? ? ??4,自動(dòng)構(gòu)建一個(gè)scrapy框架?scrapy startproject?項(xiàng)目名(做修改)
? ? ? ? 5,關(guān)于settings中代碼的修改
?????????????DOWNLOAD_DELAY =0.5 #下載延遲,就是從別人服務(wù)器上獲取數(shù)據(jù)時(shí),延遲時(shí)間????
????????????SCHEDULER ="scrapy_redis.scheduler.Scheduler"? ???#任務(wù)調(diào)度,使用scrapy-redis里面的調(diào)度器組件,不使用scrapy默認(rèn)的調(diào)度器
????????????DUPEFILTER_CLASS ="scrapy_redis.dupefilter.RFPDupeFilter"? ? ??#去重,用的是scrapy_redis里的去重組件,不適用scrapy默認(rèn)的去重
SCHEDULER_PERSIST =True? ?#是否開(kāi)啟,允許暫停,redis請(qǐng)求記錄不丟失
SCHEDULER_QUEUE_CLASS ='scrapy_redis.queue.SpiderQueue'? ? ??#調(diào)度策略:隊(duì)列,默認(rèn)是scrapy_redis請(qǐng)求,(按優(yōu)先級(jí)順序)隊(duì)列形成? ?(有三種形式,只是一個(gè)先后順序,影響不大)
#指定redis數(shù)據(jù)庫(kù)的主機(jī)
REDIS_HOST ='127.0.0.1' #修改為Redis的實(shí)際IP地址
REDIS_PORT =6379 #修改為Redis的實(shí)際端口
?? ?6,爬蟲程序的開(kāi)發(fā)
導(dǎo)入需要的模塊
# -*- coding: utf-8 -*-
import scrapy
from scrapy_redis.spidersimport RedisCrawlSpider
from scrapy.spidersimport CrawlSpider, Rule
from scrapy.linkextractorsimport LinkExtractor
from ..itemsimport? ScrapyRedisExampleItem
繼承類也是需要改變的:
class CountrySpider(RedisCrawlSpider):
? ?name ='country'
? ? redis_key ='start_urls'? #指令,用來(lái)啟動(dòng)爬蟲端程序的
? ? 7,開(kāi)多個(gè)運(yùn)行窗口進(jìn)行采集,模擬分布式,在服務(wù)端輸入指令
搭建分布式最合適:對(duì)硬件的要求,在不同網(wǎng)段里面,各自處理各自的請(qǐng)求,這樣才能體會(huì)到分布式的精髓
? ??????