分布式爬蟲

為什么要學習scrapy_redisScrapy_redis在scrapy的基礎上實現(xiàn)了更多,更強大的功能,具體體現(xiàn)在:reqeust去重,爬蟲持久化,和輕松實現(xiàn)分布式


Scrapy-redis提供了下面四種組件(components):(四種組件意味著這四個模塊都要做相應的修改)


1)Scheduler(調度器)

2)Duplication Filter(requst的去重過濾器)

3)Item Pipeline(將Item存儲在redis中以實現(xiàn)分布式處理)

4)Base Spider


代碼

與scrapy爬蟲代碼大同小異,主要是spider類和settings中設置調度器,去重功能:

1.? item

完全一樣;

2.? spiders/sina_news.py

spider類的基類改為RedisSpider

from scrapy_redis.spiders import RedisSpider

注釋掉start_urls。

新增屬性:

redis_key = ‘sinanewsspider:start_urls’

這個屬性是給redis中建組用的,:作為組名和key名的間隔。

3.?? settings.py

需要設置以下內容:

#使用scrapy_redis調度器

SCHEDULER = "scrapy_redis.scheduler.Scheduler"

#使用scrapy_redis的去重處理器

DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"


#不清理Redis隊列

SCHEDULER_PERSIST = True

如果這一項為True,那么在Redis中的URL不會被Scrapy_redis清理掉,這樣的好處是:爬蟲停止了再重新啟動,它會從上次暫停的地方開始繼續(xù)爬取。但是它的弊端也很明顯,如果有多個爬蟲都要從這里讀取URL,需要另外寫一段代碼來防止重復爬取。

如果設置成了False,那么Scrapy_redis每一次讀取了URL以后,就會把這個URL給刪除。這樣的好處是:多個服務器的爬蟲不會拿到同一個URL,也就不會重復爬取。但弊端是:爬蟲暫停以后再重新啟動,它會重新開始爬。


#redis服務器地址,主機寫本地,從機寫遠程IP

REDIS_HOST = "localhost"

#redis端口

REDIS_PORT = 6379


其他設置(可選)

爬蟲請求的調度算法

爬蟲的請求調度算法,有三種情況可供選擇:

3.1.隊列

SCHEDULER_QUEUE_CLASS='scrapy_redis.queue.SpiderQueue'

如果不配置調度算法,默認就會使用這種方式。它實現(xiàn)了一個先入先出的隊列,先放進Redis的請求會優(yōu)先爬取。

3.2.棧

SCHEDULER_QUEUE_CLASS='scrapy_redis.queue.SpiderStack'

這種方式,后放入到Redis的請求會優(yōu)先爬取。

3.3.優(yōu)先級隊列

SCHEDULER_QUEUE_CLASS='scrapy_redis.queue.SpiderPriorityQueue'

這種方式,會根據(jù)一個優(yōu)先級算法來計算哪些請求先爬取,哪些請求后爬取。這個優(yōu)先級算法比較復雜,會綜合考慮請求的深度等各個因素。


4.?? pipeline

本來就是一個分離的組件,想改就改,不改也沒問題。

scrapy-redis自帶的pipeline是將items寫入redis數(shù)據(jù)庫中的items中。

前面聲明的redis_key = ‘sinanewsspider:start_urls’

提供了組名,完整的key名為sinanewsspider:items




RedisSpider, 它能夠支持分布式的抓取,采用的是basic spider,需要寫parse函數(shù)。其次就是不再有start_urls了,取而代之的是redis_key,scrapy-redis將key從Redis里pop出來,成為請求的url地址。


RedisSpider類 不需要寫start_urls:

scrapy-redis 一般直接寫allowd_domains來指定需要爬取的域,也可以從在構造方法__init__()里動態(tài)定義爬蟲爬取域范圍(一般不用)。

必須指定redis_key,即啟動爬蟲的命令,參考格式:redis_key = 'myspider:start_urls'

根據(jù)指定的格式,start_urls將在 Master端的 redis-cli 里 lpush 到 Redis數(shù)據(jù)庫里,RedisSpider 將在數(shù)據(jù)庫里獲取start_urls。



RedisCrawlSpider類 爬蟲繼承了RedisCrawlSpider,能夠支持分布式的抓取。因為采用的是crawlSpider,所以需要遵守Rule規(guī)則,以及callback不能寫parse()方法。

同樣也不再有start_urls了,取而代之的是redis_key,scrapy-redis將key從Redis里pop出來,成為請求的url地址。

同樣的,RedisCrawlSpider類不需要寫start_urls:

scrapy-redis 一般直接寫allowd_domains來指定需要爬取的域,也可以從在構造方法__init__()里動態(tài)定義爬蟲爬取域范圍(一般不用)。必須指定redis_key,即啟動爬蟲的命令,

參考格式:redis_key = 'myspider:start_urls'根據(jù)指定的格式,start_urls將在 Master端的 redis-cli 里 lpush 到 Redis數(shù)據(jù)庫里,RedisSpider 將在數(shù)據(jù)庫里獲取start_urls。



運行爬蟲: 在爬蟲服務器上。進入爬蟲文件所在的路徑,然后輸入命令:scrapy runspider [爬蟲名字]。在Redis服務器上,推入一個開始的url鏈接:redis-cli> lpush [redis_key] start_url開始爬取。




將數(shù)據(jù)導出存儲進入mongodb

# -*- coding: utf-8 -*-

import json

import redis

import pymongo

def main():

? ? # 指定Redis數(shù)據(jù)庫信息

? ? rediscli = redis.StrictRedis(host='localhost', port=6379, db=0)

? ? # 指定MongoDB數(shù)據(jù)庫信息

? ? mongocli = pymongo.MongoClient(host='localhost', port=27017)

? ? # 指定數(shù)據(jù)庫

? ? db = mongocli['數(shù)據(jù)庫名稱']

? ? # 指定集合

? ? sheet = db['集合名稱']

? ? while True:

? ? ? ? # FIFO模式為 blpop,LIFO模式為 brpop,獲取鍵值

? ? ? ? source, data = rediscli.blpop(“項目名:items")

? ? ? ? data = data.decode('utf-8')

? ? ? ? item = json.loads(data)

? ? ? ? try:

? ? ? ? ? ? sheet.insert(item)

? ? ? ? ? ? print ("Processing:insert successed" % item)

? ? ? ? except Exception as err:

? ? ? ? ? ? print ("err procesing: %r" % item)

if __name__ == '__main__':

? ? main()


將數(shù)據(jù)導出存入 MySQL

首先啟動mysql?

?創(chuàng)建數(shù)據(jù)庫和表

# -*- coding: utf-8 -*-?

?import json?

import redis?

import pymysql?

?def main():

?# 指定redis數(shù)據(jù)庫信息?

?rediscli = redis.StrictRedis(host='localhost', port = 6379, db = 0)?

?# 指定mysql數(shù)據(jù)庫?

?mysqlcli = pymysql.connect(host='localhost', user='用戶', passwd='密碼', db = '數(shù)據(jù)庫', port=3306, charset='utf8')?

?# 使用cursor()方法獲取操作游標?

?cur = mysqlcli.cursor() while True:

?# FIFO模式為 blpop,LIFO模式為 brpop,獲取鍵值?

?source, data = rediscli.blpop("redis中對應的文件夾:items")

?item = json.loads(data.decode('utf-8'))

?try:?

?????????# 使用execute方法執(zhí)行SQL INSERT語句

?????????cur.execute("sql語句",['數(shù)據(jù)',....])?

? ? ? ? ? # 提交sql事務?

?????????mysqlcli.commit()?

?????????print("inserted successed")?

? except Exception as err:

?????????#插入失敗

?????????print("Mysql Error",err) mysqlcli.rollback()?

?if __name__ == '__main__':?

?????????????main()


分布式爬蟲的優(yōu)點:

可以充分利用多臺機器的帶寬。

可以充分利用多臺機器的ip地址。

多臺機器做,爬取效率更高。


?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容