scrapy_redis实现爬虫
Posted _夕颜
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了scrapy_redis实现爬虫相关的知识,希望对你有一定的参考价值。
scrapy-redis是scrapy框架基于redis数据库的组件,用于scrapy项目的分布式开发和部署。
有如下特征:
增量式爬虫
可以继续执行程序,会发现程序在前一次的基础之上继续往后执行,是一个基于url地址的增量式的爬虫
分布式爬取
您可以启动多个spider工程,相互之间共享单个redis的requests队列。最适合广泛的多个域名网站的内容爬取。
分布式数据处理
爬取到的scrapy的item数据可以推入到redis队列中,这意味着你可以根据需求启动尽可能多的处理程序来共享item的队列,进行item数据持久化处理
Scrapy即插即用组件
Scheduler调度器 + Duplication复制 过滤器,Item Pipeline,基本spider
1、scrapy_redis的流程
- 在scrapy_redis中,所有的带抓取的对象和去重的指纹都存在所有的服务器公用的redis中
- 所有的服务器公用一个redis中的request对象
- 所有的request对象存入redis前,都会在同一个redis中进行判断,之前是否已经存入过
- 在默认的情况下,所有数据会存放在redis中
2、scrapy_redis的原理分析
我们从settings.py中的三个配置来进行分析 在settings.py中多了一下几行,这几行表示scrapy_redis
中重新实现的了去重的类,以及调度器,并且使用的RedisPipeline
:
- RedisPipeline
- RFPDupeFilter
- Schedule
DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter" SCHEDULER = "scrapy_redis.scheduler.Scheduler" SCHEDULER_PERSIST = True ITEM_PIPELINES = { \'example.pipelines.ExamplePipeline\': 300, \'scrapy_redis.pipelines.RedisPipeline\': 400, }
2.1、Scrapy_redis之RedisPipeline
RedisPipeline中观察process_item,进行数据的保存,存入了redis中
2.2 Scrapy_redis之RFPDupeFilter
RFPDupeFilter 实现了对request对象的加密
2.3 Scrapy_redis之Scheduler
scrapy_redis调度器的实现了决定什么时候把request对象加入带抓取的队列,同时把请求过的request对象过滤掉
由此可以总结出request对象入队的条件
- request之前没有见过
- request的dont_filter为True,即不过滤
- start_urls中的url地址会入队,因为他们默认是不过滤
1、增量式爬虫
在domz爬虫文件中,实现方式crawlspider
类型的爬虫
from scrapy.linkextractors import LinkExtractor from scrapy.spiders import CrawlSpider, Rule class DmozSpider(CrawlSpider): """Follow categories and extract links.""" name = \'dmoz\' allowed_domains = [\'dmoztools.net\'] start_urls = [\'http://dmoztools.net/\'] # 定义数据提取规则,使用了css选择器 rules = [ Rule(LinkExtractor( restrict_css=(\'.top-cat\', \'.sub-cat\', \'.cat-item\') ), callback=\'parse_directory\', follow=True), ] def parse_directory(self, response): for div in response.css(\'.title-and-desc\'): yield { \'name\': div.css(\'.site-title::text\').extract_first(), \'description\': div.css(\'.site-descr::text\').extract_first().strip(), \'link\': div.css(\'a::attr(href)\').extract_first(), }
但是在settings.py中多了一下几行,这几行表示scrapy_redis
中重新实现的了去重的类,以及调度器,并且使用的RedisPipeline
DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter" SCHEDULER = "scrapy_redis.scheduler.Scheduler" SCHEDULER_PERSIST = True ITEM_PIPELINES = { \'example.pipelines.ExamplePipeline\': 300, \'scrapy_redis.pipelines.RedisPipeline\': 400, }
运行dmoz爬虫,观察现象
1、首先我们需要添加redis的地址,程序才能够使用redis
REDIS_URL = "redis://127.0.0.1:6379" #或者使用下面的方式 # REDIS_HOST = "127.0.0.1" # REDIS_PORT = 6379
2、我们执行domz的爬虫,会发现redis中多了一下三个键:
3、继续执行程序
继续执行程序,会发现程序在前一次的基础之上继续往后执行,所以domz爬虫是一个基于url地址的增量式的爬虫
2、分布式爬虫
分析demo中代码
通过观察代码:
- 继承自父类为RedisSpider
- 增加了一个redis_key的键,没有start_urls,因为分布式中,如果每台电脑都请求一次start_url就会重复
- 多了
__init__
方法,该方法不是必须的,可以手动指定allow_domains - 和scrapy中的crawlspider的区别在于,继承自的父类不相同,redis_key需要添加
实现当当网分布式爬虫
# -*- coding: utf-8 -*- from copy import deepcopy import scrapy from scrapy_redis.spiders import RedisSpider class DangdangSpider(RedisSpider): name = \'dangdang\' allowed_domains = [\'dangdang.com\'] # start_urls = [\'http://dangdang.com/\'] redis_key = \'dangdang\' def parse(self, response): # 获取大分类列表 div_list = response.xpath("//div[@class=\'con flq_body\']/div")[2:-1] for div in div_list: item = {} # 获取大分类名称 item[\'b_cate\'] = div.xpath(".//dl[contains(@class,\'primary_dl\')]/dt//text()").extract() # 获取中间分类列表 dl_list = div.xpath(".//dl[@class=\'inner_dl\']") for dl in dl_list: # 获取中间分类名称 item[\'m_cate\'] = dl.xpath(".//dt//text()").extract() # 获取小分类列表 a_list = dl.xpath("./dd/a") for a in a_list: # 获取小分类信息 item["s_cate"] = a.xpath("./text()").extract_first() item["s_href"] = a.xpath("./@href").extract_first() yield scrapy.Request( item["s_href"], callback=self.parse_book_list, meta={ "item": deepcopy(item) } ) def parse_book_list(self, response): item = response.meta[\'item\'] # 获取图书列表 li_list = response.xpath("//ul[@class=\'bigimg\']/li") for li in li_list: item[\'book_name\'] = li.xpath("./a/@title").extract_first() item[\'book_href\'] = li.xpath("./a/@href").extract_first() item[\'book_author\'] = li.xpath(".//p[@class=\'search_book_author\']/span[1]/a/text()").extract() item[\'book_press\'] = li.xpath(".//p[@class=\'search_book_author\']/span[3]/a/text()").extract_first() item[\'book_desc\'] = li.xpath(".//p[@class=\'detail\']/text()").extract_first() item[\'book_price\'] = li.xpath(".//span[@class=\'search_now_price\']/text()").extract_first() item["book_store_name"] = li.xpath(".//p[@class=\'search_shangjia\']/a/text()").extract_first() item[\'book_store_name\'] = "当当自营" if item["book_store_name"] is None else item["book_store_name"] yield item next_url = response.xpath("//li[@class=\'next\']/a/@href").extract_first() if next_url is not None: # 构造翻页请求 yield response.follow( next_url, callback=self.parse_book_list, meta={"item": item} )
在settings中进行配置
# 指定了去重的类 DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter" # 制定了调度器的类 SCHEDULER = "scrapy_redis.scheduler.Scheduler" # 调度器的内容是否持久化 SCHEDULER_PERSIST = True # redis的url地址 REDIS_URL = "redis://127.0.0.1:6379"
配置文件扩展
# 更改默认的配置 DEFAULT_LOG_FILENAME = \'日志文件.log\' # 默认日志文件名称 SPIDERS = [ "spiders.dangdang.Dangdang" ] PIPELINES = [ "pipelines.Pipeline", "pipelines.mysqlPipeline" ] SPIDER_MIDS = [ ] DOWNLOADER_MIDS = [ ] # 控制最大并发数 MAX_ASYNC_NUMBER = 1 # 异步模式 thread, coroutine ASYNC_TYPE = \'thread\' \'\'\'分布式配置\'\'\' # 执行角色 # None 代表非分布式,发起初始请求(_start_requests), 处理请求(_execute_request_response_item) # master代表主,只负责发起初始请求(_start_requests),并维护请求队列 # slave代表从,只负责处理请求(_execute_request_response_item) # ROLE = \'master\' # ROLE = \'slave\' ROLE = None # 最大重试次数 MAX_RETRY_TIMES = 3 # redis 队列的配置 REDIS_QUEUE_NAME = \'request_queue\' REDIS_QUEUE_HOST = \'localhost\' REDIS_QUEUE_PORT = 6379 REDIS_QUEUE_DB = 10 # reids 集合配置 REDIS_SET_NAME = \'filter_container\' REDIS_SET_HOST = \'localhost\' REDIS_SET_PORT = 6379 REDIS_SET_DB = 10 # 利用redis进行请求备份 的配置 REDIS_BACKUP_NAME = \'request_backup\' REDIS_BACKUP_HOST = \'localhost\' REDIS_BACKUP_PORT = 6379 REDIS_BACKUP_DB = 10
以上是关于scrapy_redis实现爬虫的主要内容,如果未能解决你的问题,请参考以下文章
Centos7__Scrapy + Scrapy_redis 用Docker 实现分布式爬虫
爬虫进阶Scrapy_redis概念作用和流程(分布式爬虫)
python3下scrapy爬虫(第十四卷:scrapy+scrapy_redis+scrapyd打造分布式爬虫之执行)