scrapy_redis使用介绍
Posted 寻寻觅觅
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了scrapy_redis使用介绍相关的知识,希望对你有一定的参考价值。
scrapy_redis是一个基于redis的scrapy组件,通过它可以快速实现简单的分布式爬虫程序,该组件主要提供三大功能:
(1)dupefilter——URL去重规则(被调度器使用)
(2)scheduler——调度器
(3)pipeline——数据持久化
一、安装redis
去官网下载redis并安装到电脑上
二、安装scrapy_redis组件
打开终端输入:pip install scrapy-redis 即可 (os/linux)
组件默认被安装在相应的Python文件夹的site-packages里面。如/usr/local/lib/python3.7/site-packages/scrapy_redis
三、scrapy_redis功能详解
(一)URL去重
1、源码 /usr/local/lib/python3.7/site-packages/scrapy_redis/dupefilter.py
setting.py中的配置信息:
# redis配置 REDIS_HOST = "127.0.0.1" REDIS_PORT = 6379 REDIS_PARAMS = {} REDIS_ENCODING = "utf-8" DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter" DUPEFILTER_KEY = "dupefilter:%(timestamp)s"
2、重写dupefilter
可以根据自己的需求自定制dupefilter
在spiders的同级目录新建文件dupefilter.py,写入代码:
""" 重写dupefilter """ from scrapy_redis.dupefilter import RFPDupeFilter from scrapy_redis.connection import get_redis_from_settings class MyDupeFilter(RFPDupeFilter): @classmethod def from_settings(cls, settings): server = get_redis_from_settings(settings) key = "my_scrapy_2_dupfilter" # 重写key debug = settings.getbool(\'DUPEFILTER_DEBUG\') return cls(server, key=key, debug=debug)
在settings.py中进行相关配置:
# redis配置 REDIS_HOST = "127.0.0.1" # 主机 REDIS_PORT = 6379 # 端口号 REDIS_PARAMS = {} # 连接参数 REDIS_ENCODING = "utf-8" # 编码规则 #配置自己的dupefilter路径 DUPEFILTER_CLASS = "my_scrapy_2.dupefilter.MyDupeFilter"
(二)调度器
1、广度优先和深度优先
(1)栈——后进先出——广度优先——LifoQueue(列表)
(2) 队列——先进先出——深度优先——FifoQueue(列表)
(3) 优先级集合——PriorityQueue(有序集合)
2、在settings.py中:
# redis配置 REDIS_HOST = "127.0.0.1" REDIS_PORT = 6379 REDIS_PARAMS = {} REDIS_ENCODING = "utf-8" # 去重规则 DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter" # 调度器 SCHEDULER = "scrapy_redis.scheduler.Scheduler" SCHEDULER_QUEUE_CLASS = \'scrapy_redis.queue.PriorityQueue\' # 默认使用优先级队列(默认),其他:PriorityQueue(有序集合),FifoQueue(列表)、LifoQueue(列表) SCHEDULER_QUEUE_KEY = \'%(spider)s:requests\' # 调度器中请求存放在redis中的key chouti:requests SCHEDULER_SERIALIZER = "scrapy_redis.picklecompat" # 对保存到redis中的数据进行序列化,默认使用pickle SCHEDULER_PERSIST = True # 是否在关闭时候保留原来的调度器和去重记录,True=保留,False=清空 SCHEDULER_FLUSH_ON_START = True # 是否在开始之前清空 调度器和去重记录,True=清空,False=不清空 # SCHEDULER_IDLE_BEFORE_CLOSE = 10 # 去调度器中获取数据时,如果为空,最多等待时间(最后没数据,未获取到)。 SCHEDULER_DUPEFILTER_KEY = \'%(spider)s:dupefilter\' # 去重规则,在redis中保存时对应的key SCHEDULER_DUPEFILTER_CLASS = \'scrapy_redis.dupefilter.RFPDupeFilter\' # 去重规则对应处理的类 DEPTH_PRIORITY = -1 # 如果是使用优先级集合(PriorityQueue)就用做该配置参数 DEPTH_PRIORITY可以设为-1或者1
(三)数据持久化
1、源码
以爬取抽屉新热榜的新闻标题与连接为例:
爬虫 chouti.py:
# -*- coding: utf-8 -*- """ 爬取抽屉新热榜的新闻标题以及url 并保存 """ import scrapy from scrapy.http import Request from ..items import MyScrapy3Item class ChoutiSpider(scrapy.Spider): name = \'chouti\' allowed_domains = [\'chouti.com\'] start_urls = [\'http://chouti.com/\'] def parse(self, response): # print(response, response.request.priority, response.meta.get(\'depth\')) items = response.xpath("//div[@id=\'content-list\']/div[@class=\'item\']") for item in items: title = item.xpath(".//div[@class=\'part1\']/a/text()").extract_first().strip() # 标题 href = item.xpath(".//div[@class=\'part1\']/a/@href").extract_first().strip() # 连接 yield MyScrapy3Item(title=title, href=href) # yield一个item对象 # 翻页 page_list = response.xpath(\'//*[@id="dig_lcpage"]//a/@href\').extract() for url in page_list: url = "https://dig.chouti.com" + url yield Request(url=url, callback=self.parse)
items.py:
import scrapy class MyScrapy3Item(scrapy.Item): title = scrapy.Field() href = scrapy.Field()
settings.py中做相关的配置:
ITEM_PIPELINES = { "scrapy_redis.pipelines.RedisPipeline": 300, # 设置使用scrapy_redis的持久化类 }
# -----------其他配置----------------------
DEPTH_LIMIT = 2 # 爬取深度
# redis配置 (必须的)
REDIS_HOST = "127.0.0.1"
REDIS_PORT = 6379
REDIS_PARAMS = {}
REDIS_ENCODING = "utf-8"
# 去重规则
DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"
# 调度器
SCHEDULER = "scrapy_redis.scheduler.Scheduler"
SCHEDULER_QUEUE_CLASS = \'scrapy_redis.queue.FifoQueue\' # 默认使用优先级队列(默认),其他:PriorityQueue(有序集合),FifoQueue(列表)、LifoQueue(列表)
SCHEDULER_QUEUE_KEY = \'%(spider)s:requests\' # 调度器中请求存放在redis中的key chouti:requests
SCHEDULER_SERIALIZER = "scrapy_redis.picklecompat" # 对保存到redis中的数据进行序列化,默认使用pickle
SCHEDULER_PERSIST = True # 是否在关闭时候保留原来的调度器和去重记录,True=保留,False=清空
SCHEDULER_FLUSH_ON_START = True # 是否在开始之前清空 调度器和去重记录,True=清空,False=不清空
# SCHEDULER_IDLE_BEFORE_CLOSE = 10 # 去调度器中获取数据时,如果为空,最多等待时间(最后没数据,未获取到)
SCHEDULER_DUPEFILTER_KEY = \'%(spider)s:dupefilter\' # 去重规则,在redis中保存时对应的key
SCHEDULER_DUPEFILTER_CLASS = \'scrapy_redis.dupefilter.RFPDupeFilter\' # 去重规则对应处理的类
在项目根目录新建文件start_chouti.py用于运行爬虫(也可以直接在终端输命令来运行):
from scrapy.cmdline import execute if __name__ == "__main__": execute(["scrapy", "crawl", "chouti", "--nolog"])
可以新建一个py文件用于查看保存在Redis中的数据:
# 3种方式查看数据
import redis conn = redis.Redis(host="127.0.0.1", port=6379) # conn.flushall() # 清空Redis print(conn.keys()) # 查看所有key [b\'chouti:dupefilter\', b\'chouti:items\']
# 1、获取指定范围的数据 # res = conn.lrange(\'chouti:items\', 0, 3) # 获取持久化的数据 取3条 # print(res) """
结果:
[b\'{"title": "\\\\u3010\\\\u56fe\\\\u96c6\\\\u30112018\\\\u5e74\\\\u5ea6\\\\u5929\\\\u6587\\\\u6444\\\\u5f71\\\\u5e08\\\\u5927\\\\u8d5b\\\\u83b7\\\\u5956\\\\u4f5c\\\\u54c1\\\\u516c\\\\u5e03", "href": "https://mp.weixin.qq.com/s/eiWj7ky53xEDoMRFXC1EGg"}\', b\'{"title": "\\\\u3010\\\\u201c\\\\u4eba\\\\u76f4\\\\u5230\\\\u5165\\\\u571f\\\\u4e3a\\\\u5b89\\\\u90a3\\\\u4e00\\\\u5929\\\\uff0c\\\\u90fd\\\\u5728\\\\u8d70\\\\u53f0\\\\u9636\\\\u201d \\\\u3011\\\\u674e\\\\u548f\\\\u5728\\\\u63a5\\\\u53d7\\\\u91c7\\\\u8bbf\\\\u65f6\\\\u66fe\\\\u8fd9\\\\u6837\\\\u5f62\\\\u5bb9\\\\u81ea\\\\u5df1\\\\u7684\\\\u4eba\\\\u751f\\\\uff1a\\\\u201c\\\\u4eba\\\\u76f4\\\\u5230\\\\u5165\\\\u571f\\\\u4e3a\\\\u5b89\\\\u90a3\\\\u4e00\\\\u5929\\\\uff0c\\\\u90fd\\\\u5728\\\\u8d70\\\\u53f0\\\\u9636\\\\u3002\\\\u8ddf\\\\u767b\\\\u9ec4\\\\u5c71\\\\u4e00\\\\u6837\\\\uff0c\\\\u767b\\\\u7684\\\\u65f6\\\\u5019\\\\u4f60\\\\u4e0d\\\\u89c9\\\\u5f97\\\\u6709\\\\u4e91\\\\uff0c\\\\u5230\\\\u4e00\\\\u5b9a\\\\u9ad8\\\\u5ea6\\\\u7684\\\\u65f6\\\\u5019\\\\uff0c\\\\u65c1\\\\u8fb9\\\\u6709\\\\u4eba\\\\u63d0\\\\u9192\\\\u4f60\\\\u56de\\\\u5934\\\\u770b\\\\u4e00\\\\u4e0b\\\\uff0c\\\\u4e91\\\\u5c31\\\\u5728\\\\u773c\\\\u524d\\\\u3002\\\\u201d", "href": "https://mp.weixin.qq.com/s/erLgWmL1GhpyWqwOTIlRvQ"}\', b\'{"title": "\\\\u3010\\\\u6e38\\\\u620f\\\\u673a\\\\u5236 \\\\u6e17\\\\u900f\\\\u5e76\\\\u6e10\\\\u6e10\\\\u5851\\\\u9020\\\\u4e86\\\\u73b0\\\\u5b9e\\\\u4e16\\\\u754c\\\\uff0c\\\\u4f60\\\\u662f\\\\u5426\\\\u4e5f\\\\u4e00\\\\u6837\\\\u8ba4\\\\u4e3a\\\\u7406\\\\u6240\\\\u5f53\\\\u7136\\\\uff1f\\\\u3011\\\\u5728\\\\u667a\\\\u80fd\\\\u624b\\\\u673a\\\\u666e\\\\u53ca\\\\u4ee5\\\\u540e\\\\uff0c\\\\u79fb\\\\u52a8\\\\u6280\\\\u672f\\\\u80fd\\\\u591f\\\\u4e0e\\\\u73b0\\\\u5b9e\\\\u4e16\\\\u754c\\\\u53d1\\\\u751f\\\\u8d8a\\\\u6765\\\\u8d8a\\\\u591a\\\\u7684\\\\u4ea4\\\\u4e92\\\\uff0c\\\\u56e0\\\\u6b64\\\\u6e38\\\\u620f\\\\u5316\\\\u7684\\\\u5c1d\\\\u8bd5\\\\u5e76\\\\u6ca1\\\\u6709\\\\u51cf\\\\u5c11\\\\u53cd\\\\u800c\\\\u589e\\\\u591a\\\\u4e86\\\\u3002\\\\u6709\\\\u6bcf\\\\u5929\\\\u8bb0\\\\u5f55\\\\u4f60\\\\u7684\\\\u6b65\\\\u884c\\\\u8ddd\\\\u79bb\\\\uff0c\\\\u7136\\\\u540e\\\\u9881\\\\u53d1\\\\u5956\\\\u7ae0\\\\u7684\\\\u3002\\\\u6709\\\\u8bb0\\\\u5f55\\\\u4f60\\\\u7684\\\\u4e60\\\\u60ef\\\\uff0c\\\\u5e76\\\\u53ef\\\\u4ee5\\\\u5efa\\\\u8bbe\\\\u4e00\\\\u5ea7\\\\u57ce\\\\u5e02\\\\u7684\\\\u3002", "href": "http://www.qdaily.com/articles/57753.html"}\', b\'{"title": "\\\\u3010\\\\u53c8\\\\u5931\\\\u4e00\\\\u57ce\\\\uff01\\\\u9ed8\\\\u514b\\\\u5c14\\\\u7684\\\\u201c\\\\u9ec4\\\\u91d1\\\\u914d\\\\u89d2\\\\u201d\\\\u5728\\\\u9ed1\\\\u68ee\\\\u5dde\\\\u906d\\\\u9047\\\\u60e8\\\\u8d25\\\\u3011\\\\u4eca\\\\u5e74\\\\u4e09\\\\u6708\\\\u8270\\\\u96be\\\\u5b8c\\\\u6210\\\\u7b2c\\\\u56db\\\\u6b21\\\\u7ec4\\\\u9601\\\\u7684\\\\u5fb7\\\\u56fd\\\\u603b\\\\u7406\\\\u9ed8\\\\u514b\\\\u5c14\\\\uff0c\\\\u572810\\\\u6708\\\\u5fb7\\\\u56fd\\\\u4e24\\\\u4e2a\\\\u5173\\\\u952e\\\\u5dde\\\\u2014\\\\u2014\\\\u5df4\\\\u4f10\\\\u5229\\\\u4e9a\\\\u5dde\\\\u548c\\\\u9ed1\\\\u68ee\\\\u5dde\\\\u7684\\\\u9009\\\\u4e3e\\\\u4e2d\\\\uff0c\\\\u63a5\\\\u8fde\\\\u906d\\\\u9047\\\\u5386\\\\u53f2\\\\u6027\\\\u60e8\\\\u8d25\\\\u3002\\\\u9ed8\\\\u514b\\\\u5c14\\\\u7684\\\\u201c\\\\u9ec4\\\\u91d1\\\\u914d\\\\u89d2\\\\u201d\\\\u2014\\\\u2014\\\\u793e\\\\u6c11\\\\u515a\\\\uff08SPD\\\\uff09\\\\u5728\\\\u4e24\\\\u6b21\\\\u9009\\\\u4e3e\\\\u4e2d\\\\u7684\\\\u5f97\\\\u7968\\\\u7387\\\\u5448\\\\u73b0\\\\u81ea\\\\u7531\\\\u843d\\\\u4f53\\\\u72b6\\\\u6001\\\\u3002", "href": "https://wallstreetcn.com/articles/3428455"}\'] """
# 2、一条一条的将数据取走
# item = conn.lpop(\'chouti:items\')
# print(item)
"""
结果:
b\'{"title": "\\\\u3010\\\\u56fe\\\\u96c6\\\\u30112018\\\\u5e74\\\\u5ea6\\\\u5929\\\\u6587\\\\u6444\\\\u5f71\\\\u5e08\\\\u5927\\\\u8d5b\\\\u83b7\\\\u5956\\\\u4f5c\\\\u54c1\\\\u516c\\\\u5e03", "href": "https://mp.weixin.qq.com/s/eiWj7ky53xEDoMRFXC1EGg"}\' """
# 3、做成一个生产者-消费者模型
while True:
item = conn.blpop(\'chouti:items\') # 一条一条的将数据取走 如果没有了就阻塞住
print(item)
通过使用scrapy_redis的持久化数据功能,可以将生产数据和获取数据作为两件互不影响的事情并发的运行。
2、如果还想要将数据存入其他地方,可以继承和重写scrapy_redis的pipelines
四、起始URL的定制
让爬虫像永动机一样一直处于备战状态,如果没有请求就处于等待状态,当有新的URL进来时就开始爬取数据。
在爬虫文件中:
""" 爬取抽屉新热榜的新闻标题以及url 并保存 让爬虫一直爬数据,如果没有就处于等待状态 """ from scrapy_redis.spiders import RedisSpider class ChoutiSpider(RedisSpider): # 继承RedisSpider name = \'chouti\' allowed_domains = [\'chouti.com\'] def parse(self, response): print(response)
配置文件中:
# 起始url REDIS_START_URLS_AS_SET = True # True:在Redis里面按照集合去存,False:按照列表来存储 START_URLS_KEY = \'%(name)s:start_urls\' # 在源码中默认的起始URL的key为 chouti:start_urls
再写一个py文件来设置url:
import redis conn = redis.Redis(host="127.0.0.1", port=6379) # conn.flushall() # 清空Redis print(conn.keys()) # 查看所有key [b\'chouti:start_url\'] item = conn.sadd("chouti:start_url", "https://dig.chouti.com/r/pic/hot/1") # 设置起始url print(item)
以上是关于scrapy_redis使用介绍的主要内容,如果未能解决你的问题,请参考以下文章