Scrapy架構學習(八)—-Scrapy-redis分布式爬蟲學習
Scrapy-redis
分布式爬蟲架構,是在
Scrapy
爬蟲架構的基礎上進行改進的,通過
Redis
來進行資料的緩存,可以在多台機器上運作爬蟲程式。本文示例是在
CentOS
的虛拟機運作。
1、Redis安裝
關于Redis的安裝,網上有不少的文章,在配置Redis環境上也會有些問題,下面的2篇文章,詳細的介紹了Redis的安裝和問題,這裡就直接搬運過來了。因為我的
Scrapy-Redis
的爬蟲代碼,是運作在
CentOS
中
CentOS 7下Redis的安裝與配置
CentOS 7.0 安裝Redis 3.2.1詳細過程和使用常見問題
2、Redis分布式測試
我們采用3台機器,進行分布式爬蟲爬取資料,在虛拟機上安裝好
Redis
後,我們來進行
Redis
的分布式測試。
我們将server1作為
Master
機器(
ip:192.168.108.20
)。server2(
ip:192.168.108.21
),server3(
ip:192.168.108.22
)作為2台機器為
Slaves
。
2.1 啟動Master機器的Redis服務
找到redis的配置檔案
redis.conf
,注釋
bind 127.0.0.1
,保護模式
protected-mode
設定為
no
。
指定
redis.conf
啟動
redis-server /redis/redis-stable/redis.conf
如圖:
2.2 啟動每台機器的Redis用戶端redis-cli
Master機器:
Slaves機器,指定Master機器的ip
如果出現如下情況:
Could not connect to Redis at :: No route to host
需要對每台機器清除下防火牆配置:
sudo iptables -F
再次連接配接Master的Redis,如圖:
如果機器連接配接不通,可能是防火牆的問題,可以試試:sudo iptables -F 清除防火牆配置
2.3 測試分布式Redis
3、scrapy-redis的爬蟲代碼
Scrapy-redis分布式爬蟲,爬取的是:
http://sh.58.com/chuzu/
。
下面我們看下代碼,基本和Scrapy的項目一樣,就Spider的類改為Scrapy-redis中的類,settings.py中的配置不一樣。
3.1 Item
定義實體類
class Redis58TestItem(scrapy.Item):
# 标題
title = scrapy.Field()
# 房間
room = scrapy.Field()
# 區域
zone = scrapy.Field()
# 位址
address = scrapy.Field()
# 價格
money = scrapy.Field()
# 釋出資訊的類型,品牌較高價的電梯大廈,經紀人,個人
type = scrapy.Field()
3.2 spider
spider爬蟲類實作
from scrapy.spiders import Rule
from scrapy_redis.spiders import RedisCrawlSpider
from scrapy.linkextractors import LinkExtractor
from redis58test.items import Redis58TestItem
class Redis58Spider(RedisCrawlSpider):# 繼承的Spider是Scrapy-redis架構提供的
# spider的唯一名稱
name = 'redis58spider_redis'
# 開始爬取的url
redis_key = 'redis58spider:start_urls'
# 從頁面需要提取的url 連結(link)
links = LinkExtractor(allow="sh.58.com/chuzu/pn\d+")
# 設定解析link的規則,callback是指解析link傳回的響應資料的的方法
rules = [Rule(link_extractor=links, callback="parseContent", follow=True)]
def parseContent(self, response):
"""
解析響應的資料,擷取需要的資料字段
:param response: 響應的資料
:return:
"""
# 根節點 //ul[@class="listUl"]/li[@logr]
# title: .//div[@class="des"]/h2/a/text()
# room: .//div[@class="des"]/p[@class="room"]/text()
# zone: .//div[@class="des"]/p[@class="add"]/a[1]/text()
# address: .//div[@class="des"]/p[@class="add"]/a[last()]/text()
# money: .//div[@class="money"]/b/text()
# type: # .//div[@class="des"]/p[last()]/@class # 如果是add,room .//div[@class="des"]/div[@class="jjr"]/@class
for element in response.xpath('//ul[@class="listUl"]/li[@logr]'):
title = element.xpath('.//div[@class="des"]/h2/a/text()')[].extract().strip()
room = element.xpath('.//div[@class="des"]/p[@class="room"]')[].extract()
zone = element.xpath('.//div[@class="des"]/p[@class="add"]/a[1]/text()')[].extract()
address = element.xpath('.//div[@class="des"]/p[@class="add"]/a[last()]/text()')[].extract()
money = element.xpath('.//div[@class="money"]/b/text()')[].extract()
type = element.xpath('.//div[@class="des"]/p[last()]/@class')[].extract()
if type == "add" or type == "room":
type = element.xpath('.//div[@class="des"]/div[@class="jjr"]/@class')[].extract()
item = Redis58TestItem()
item['title'] = title
item['room'] = room
item['zone'] = zone
item['address'] = address
item['money'] = money
item['type'] = type
yield item
3.3 Pipeitem
實際上我們不需要處理Pipeitem的資料,因為Scrapy架構會将資料給redis去重。
class Redis58TestPipeline(object):
def process_item(self, item, spider):
return item
3.4 settings.py設定
配置Scrapy-Redis的資訊
DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"
SCHEDULER = "scrapy_redis.scheduler.Scheduler"
SCHEDULER_PERSIST = True
# 使用什麼隊列排程
#SCHEDULER_QUEUE_CLASS = "scrapy_redis.queue.SpiderPriorityQueue" # 優先級隊列
#SCHEDULER_QUEUE_CLASS = "scrapy_redis.queue.SpiderQueue" # 基本隊列
#SCHEDULER_QUEUE_CLASS = "scrapy_redis.queue.SpiderStack" # 棧
ITEM_PIPELINES = {
'redis58test.pipelines.Redis58TestPipeline': ,
'scrapy_redis.pipelines.RedisPipeline': ,
}
REDIS_HOST = '192.168.108.20' # redis Master機器的ip
REDIS_PORT =
4、執行爬蟲
4.1 啟動Master機器的redis-server
# 啟動Master機器上的redis-server
redis-server /redis/redis-stable/redis.conf
4.2 執行爬蟲程式
将Scrapy-redis項目的爬蟲代碼,放到slaves機器上。進入項目的spider目錄,然後分别在slaves機器上啟動scrapy-redis項目爬蟲程式,不分先後。
4.3 Master機器的redis-cli
在Master機器的redis-cli裡啟動需要爬取的url。
5、将redis資料永久存儲
爬蟲程式爬取之後,我們将redis中的資料進行儲存到mongodb資料庫中。如下
import json
import redis
import pymongo
def main():
# 指定Redis資料庫資訊
rediscli = redis.StrictRedis(host='192.168.108.20', port=, db=)
# 指定MongoDB資料庫資訊
mongocli = pymongo.MongoClient(host='localhost', port=)
# 建立資料庫名
db = mongocli['redis58test']
# 建立表名
sheet = db['redis58_sheet2']
while True:
# FIFO模式為 blpop,LIFO模式為 brpop,擷取鍵值
source, data = rediscli.blpop(["redis58spider_redis:items"])
item = json.loads(data)
sheet.insert(item)
try:
print(u"Processing: %(name)s <%(link)s>" % item)
except KeyError:
print(u"Error procesing: %r" % item)
if __name__ == '__main__':
main()
資料如圖: