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
共同学习,写下你的评论
评论加载中...
作者其他优质文章