为了账号安全,请及时绑定邮箱和手机立即绑定

redis分布式爬虫初体验

标签:
Python

scrapy+redis实现分布式爬虫

前言介绍

  • 分布式爬虫又可以称为集群爬虫,和单点爬虫不同的是分布式爬虫可以实现多台机器同时运行,速度更快也能避免反爬虫机制对ip检测封锁,而且能随时停止和运行,自动url去重(这意味着再次运行必须先清空redis数据库下的XX:dupefilter,否则无法重复爬取相同url)。

  • 本文介绍redis分布式爬虫 ,redis是一种非关系数据库除了支持string类型的value外还支持string、hash、set、sortedset、list等数据结构。重要的是能支持主从复制,主机会自动将数据同步到从机,可以进行读写分离。

  • 我们利用redis的特性,更改scrapy的任务调度,我们在scrapy项目spider中建立两个爬虫一个专门爬取url网络链接,一个爬取数据。master(主机)将设置链接爬虫爬取对应的网络链接后在redis中分享url链接给slave(从机),slave领取任务后开始数据爬取并将数据存储在redis中,最后master便能通过访问redis命令提取目标数据。

1.scrapy+redis分布式准备工作:

(1).下载redis及环境搭建

redis下载地址 windows
redis desktop manager(Windows可视化管理redis数据库工具)下载地址
redis 官网最新下载地址 Linux
Linux Ubuntu系统安装介绍看这里

(2).scrapy_redis环境安装

windows安装后
  • 找到并修改安装目录下bin文件下的redis.conf

#需要远程连接redis 先注释bind# bind 127.0.0.1

如果需要修改密码,也在redis.conf文件找到:

#取消注释requirepassrequirepass redisredis  # redisredis就是密码(记得自己修改)
  • 运行redis服务器的命令:安装目录下的redis-server.exe

  • 运行redis客户端的命令:安装目录下的redis-cli.exe,也可以在当前目录下打开dos输入redis-cli   然后auth 密码

Linux安装后
  • 进入目录下 同样修改redis.conf文件

  • 输入/etc/redis-serverce redis.conf启动redis服务器

  • 当前目录 重新打开一个新窗口 输入/etc/redis-cli  (一般在etc目录下)

然后在Linux或Windows的命令窗口输入命令安装对应的python库
 pip install scrapy-redis 
 pip install redis

我们可以在windows下测试远程连接redis是否正常
打开dos窗口输入
redis-cli -h 远程ip地址 -p 6379
注意要提前打开远程机器的redis-server,当然你也可以通过redis desktop manager图形化界面工具来连接管理你的redis数据库。

(3)介绍redis有关操作命令

网上可以搜到很多有关redis的操作命令,我这里介绍比较常见的

D:\Program Files\Redis>redis-cli      #启动redis客户端redis 127.0.0.1:6379> auth 123456   #输入密码OK
redis 127.0.0.1:6379> keys *  #查询当前所有数据表(empty list or set)
redis 127.0.0.1:6379> select 1 #选择数据库db=1 默认是0OK
redis 127.0.0.1:6379[1]> keys *1) "ifengspider:items"3) "ifengurls:dupefilter"4) "newspider:dupefilter"5) "ifeng:requests"redis 127.0.0.1:6379[1]> lrange ifengspider:items 1 2       #读取ifengspider:item表前2行数据#这里数据过多将无法显示,在windows下使用redis desktop manager可查看更多,但也很容易崩溃,不是很稳定redis 127.0.0.1:6379[1]> flushdb #只清空当前数据库数据redis 127.0.0.1:6379[1]> flushall #清空所有数据库数据

2、scrapy中使用加入redis

(1)在setting.py文件的添加:

SCHEDULER = "scrapy_redis.scheduler.Scheduler"SCHEDULER_PERSIST = TrueSCHEDULER_QUEUE_CLASS = 'scrapy_redis.queue.SpiderPriorityQueue'REDIS_URL =  'redis://:password@hostname:6973' # 此处设置将连接有密码的hostREDIS_HOST = '127.0.0.1' #如果设置了REDIS_URL此处将被覆盖REDIS_PORT = 6379 #同上#启用Redis调度存储请求队列SCHEDULER = "scrapy_redis.scheduler.Scheduler"
 #确保所有的爬虫通过Redis去重DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"--------------------------------以下选填-----------------------------------------------#默认请求序列化使用的是pickle 但是我们可以更改为其他类似的。PS:这玩意儿2.X的可以用。3.X的不能用#SCHEDULER_SERIALIZER = "scrapy_redis.picklecompat"
 #不清除Redis队列、这样可以暂停/恢复 爬取#SCHEDULER_PERSIST = True
 #使用优先级调度请求队列 (默认使用)#SCHEDULER_QUEUE_CLASS = 'scrapy_redis.queue.PriorityQueue'#可选用的其它队列#SCHEDULER_QUEUE_CLASS = 'scrapy_redis.queue.FifoQueue'#SCHEDULER_QUEUE_CLASS = 'scrapy_redis.queue.LifoQueue'
 #最大空闲时间防止分布式爬虫因为等待而关闭#SCHEDULER_IDLE_BEFORE_CLOSE = 10
 #此处设置将返回的数据自动保存在连接主机的redis数据库中ITEM_PIPELINES = {    'scrapy_redis.pipelines.RedisPipeline': 300} 
#序列化项目管道作为redis Key存储#REDIS_ITEMS_KEY = '%(spider)s:items'
 #默认使用ScrapyJSONEncoder进行项目序列化#You can use any importable path to a callable object.#REDIS_ITEMS_SERIALIZER = 'json.dumps'
 #指定连接到redis时使用的端口和地址(可选)#REDIS_HOST = 'localhost'#REDIS_PORT = 6379
 #指定用于连接redis的URL(可选)#如果设置此项,则此项优先级高于设置的REDIS_HOST 和 REDIS_PORT#REDIS_URL = 'redis://user:pass@hostname:9001'
 #自定义的redis参数(连接超时之类的)#REDIS_PARAMS  = {}
 #自定义redis客户端类#REDIS_PARAMS['redis_cls'] = 'myproject.RedisClient'
 #如果为True,则使用redis的'spop'进行操作。#如果需要避免起始网址列表出现重复,这个选项非常有用。开启此选项urls必须通过sadd添加,否则会出现类型错误。#REDIS_START_URLS_AS_SET = False
 #RedisSpider和RedisCrawlSpider默认 start_usls 键#REDIS_START_URLS_KEY = '%(name)s:start_urls'
 #设置redis使用utf-8之外的编码#REDIS_ENCODING = 'latin1'

(2)在其他文件中,若要通过代码来连接redis数据库以此操作redis数据库中数据:

pool =redis.ConnectionPool(host='hostname', port=6379, db=0,password=‘pwd’)#password没有设置可不填r = redis.Redis(connection_pool=pool)
r.lpush('XX:items’,data) #将数据data导入连接的数据库中 字段名XX:items
data = r.lpop('XX:items') #从数据库中XX:items字段最上方数据弹出
r.delete('aa:items','bb:items')  #清空 aa:items,bb:items中数据 如果需要反复跑程序可在爬虫开始时设置,来删除对应的dupefilter

(3)关于item.py和middlewares.py:

这里和scrapy下写法没什么区别,都照原来写就好了

(4)关于自定义spider写法:

主要不同的是爬虫类需要继承scrapy_redis中的RedisCrawlSpider而不是scrapy.Spider,然后start_urls改成redis_key来从redis服务端提取url任务链接地址。这样主机有专门爬取链接的爬虫,其它从机只需要领取其中的任务,解析任务页面返回数据,即可实现分布式爬虫。

import scrapyfrom scrapy_redis.spiders import RedisCrawlSpider  
class XX_spider(RedisCrawlSpider):  #继承scrapy_redis
    name = 'ifengspider'
    allowed_domains=['finance.ifeng.com','app.finance.ifeng.com']
    redis_key = 'XX:requests'  #填任务url链接所在表名,在setting.py中已经设置好要连接的redis-server和对应db
    def parse(self,response):  #这里直接写scrapy默认的parse,到这里就可以直接写对应网页解析了

(5)pipelines.py 将Spider文件返回的数据传入redis数据库中:

首先在setting.py文件下设置
ITEM_PIPELINES = {'scrapy_redis.pipelines.RedisPipeline': 300 
}
pipelines.py :
class Redis_pipelines(object):
  def process_item(self,item,spider):
    item['a']=item['a']  #这里作为处理结果的收尾地方,可以按自己意愿改写数据
    item['b']=item['b']
    item['c']=item['c']
    item['d']=item['d']    return item

这里会使每台机器跑下来的数据会发送到setting.py设置的主机地址redis服务器上,字段名为XXspider:items。最后所有url跑完后,在服务器写一个mysql.py文件:连接本地redis服务器导出所有数据给自己的Mysql数据库。下面我贴上Pipelines.py的改写代码和提取redis数据循环导入mysql数据库中代码。

Mysql.py:
import pymysqlimport redisimport jsondef Data_into_Mysql():

        conn = pymysql.connect(host='127.0.0.1',
                                 charset='utf8',user='root',passwd='pwd',db='crawler',port=3306)
        pool =redis.ConnectionPool(host='127.0.0.1', port=6379, password='pwd',db=2)
        r = redis.Redis(connection_pool=pool)
        data = r.lpop('xx:items')
        count=0
        while data is not None:            try:
                data=data.decode('utf-8','ignore')
                a=json.loads(data)           
                with conn.cursor() as cursor:                         
                        sql = '''INSERT INTO table  VALUES(%s,%s)'''
                        cursor.execute(sql, (a['key'],a['key']))                 
                        conn.commit() 
                count+=1
                print(count)
                data = r.lpop('xx:items')            except Exception as e:
                print(str(e))
                print(a)
                data = r.lpop('xx:items')
        conn.close();
Data_into_Mysql()

注意如果要重新跑相同的url,请先清空对应dupefilter里的数据,此处为redis去重设置。

3.小结

作为爬虫新手,第一次写自己爬虫学习上的一些经历,若有不足之处欢迎指出,欢迎感兴趣的朋友一起探讨研究,分布式爬虫学习也是在网上到处翻了各种资料对比填坑才成功实现,我希望自己总结的经验能方便更多感兴趣的小伙伴,若写有不明之处,可以留言或私信我,当然特别细节的东西可能我也需要继续学习。后续可能会继续更新分布式爬虫相关的内容和填坑,谢谢大家支持。

参考资料:

基于Python使用scrapy-redis框架实现分布式爬虫
使用scrapy-redis构建简单的分布式爬虫



作者:黑羊的皇冠
链接:https://www.jianshu.com/p/966fd26b2f8d


点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消