Python scrapy框架教学(五): 分布式爬虫

数据去重

当数据重复时,我们就可以不保存

from scrapy.exceptions import DropItem
class DuplicatesPipeline(object):
  def __init__(self):
    self.ids_seen = set()
  def process_item(self, item, spider):
    if item['id'] in self.ids_seen:
      raise DropItem("Duplicate item found: %s" % item)
    else:
      self.ids_seen.add(item['id'])
    return item

Python爬虫、数据分析、网站开发等案例教程视频免费在线观看

https://space.bilibili.com/523606542

分布式采集

Scrapy_redis : Redis-based components for Scrapy.

Github地址:https://github.com/rmax/scrapy-redis Scrapy_redis 在scrapy 的基础上实现了更多,更强大的功能,具体体现在:reqeust去重,爬虫持久化,和轻松实现分
布式

那么,scrapy_redis是如何帮助我们抓取数据的呢?

单机爬虫

默认情况下Scrapy是不支持分布式的,需要使用基于Redis 的 Scrapy-Redis 组件才能实现分布式。

正常的 Scrapy 单机爬虫:

Python scrapy框架教学(五): 分布式爬虫

Scrapy并不会共享调度队列,也就是说Scrapy是不支持分布式的。为了支持分布式,我们需要让Scrapy支持共享调度队列,也就是改造成共享调度和去重的功能。

分布式爬虫

分布式:分而治之

将一个爬虫代码,分别部署在多台电脑上,共同完成整个爬虫任务。

Python scrapy框架教学(五): 分布式爬虫

使用Redis服务器来集中处理所有的请求,主要负责请求的去重和调度。通过这种方式,所有电脑端的爬虫共享了一个爬取队列,并且每个电脑端每次得到的请求都是其他爬虫未曾访问的。从而提高了爬虫效率。

得到一个请求之后,检查一下这个Request是否在Redis去重,如果在就证明其它的spider采集过啦!如果不在就添加进调度队列,等待别人获取。

Scrapy 是一个通用的爬虫框架,但是不支持分布式,Scrapy-redis是为了更方便地实现Scrapy分布式爬取,而提供了一些以redis为基础的组件。

安装如下: pip install scrapy-redis Scrapy-redis

提供了下面四种组件(components):(四种组件意味着这四个模块都要做相应的修改)

  • Scheduler(调度器)
  • Duplication Filter(去重)
  • Item Pipeline(管道)
  • Base Spider(爬虫类)

Scheduler(调度器)
Scrapy改造了Python本来的collection.deque(双向队列)形成了自己的Scrapy queue,但是Scrapy多个spider不能共享待爬取队列Scrapy queue, 即Scrapy本身不支持爬虫分布式,scrapy-redis 的解决是把这个Scrapy queue换成redis数据库(也是指redis队列),便能让多个spider去同一个数据库里读取,这样实现共享爬取队列。

Redis支持多种数据结构,这些数据结构可以很方便的实现这样的需求:

  • 列表有lpush(),lpop(),rpush(),rpop(),这些方法可以实现先进先出,或者先进后出式的爬取队列。
  • 集合元素是无序且不重复的,可以很方便的实现随机排序且不重复的爬取队列。
  • Scrapy的Request带有优先级控制,Redis中的集合也是带有分数表示的,可以用这个功能实现带有优先级调度的爬取队列。

Scrapy把待爬队列按照优先级建立了一个字典结构,比如:

{
  优先级0 : 队列0
  优先级1 : 队列1
  优先级2 : 队列2
}

然后根据request中的优先级,来决定该入哪个队列,出列时则按优先级较小的优先出列。由于Scrapy原来的Scheduler只能处理Scrapy自身的队列,不能处理Redis中的队列,所以原来的Scheduler已经无法使用,应该使用Scrapy-Redis的Scheduler组件。

Duplication Filter(去重)
Scrapy自带去重模块,该模块使用的是Python中的集合类型。该集合会记录每个请求的指纹,指纹也就是Request的散列值。指纹的计算采用的是hashlib的sha1()方法。计算的字段包含了,请求的Method,URL,Body,Header这几个内容,这些字符串里面只要里面有一点不同,那么计算出来的指纹就是不一样的。也就是说,计算的结果是加密后的字符串,这就是请求指纹。通过加密后的字符串,使得每个请求都是唯一的,也就是指纹是惟一的。并且指纹是一个字符串,在判断字符串的时候,要比判断整个请求对象容易。所以采用了指纹作为判断去重的依据。

Scrapy-Redis要想实现分布式爬虫的去重功能,也是需要更新指纹集合的,但是不能每个爬虫维护自己的单独的指纹集合。利用Redis集合的数据结构类型,可以轻松实现分布式爬虫的指纹判重。也就是说:每台主机得到Request的指纹去和Redis中的集合进行对比,如果指纹存在,说明是重复的,也就不会再去发送请求,如果不曾存在于Redis中的指纹集合,就会发送请求,并且将该指纹加入Redis的集合中。这样就实现了分布式爬虫的指纹集合的共享。

Item Pipeline
引擎将(Spider返回的)爬取到的Item给Item Pipeline,scrapy-redis 的Item Pipeline将爬取到的 Item 存⼊redis的 items queue。修改过Item Pipeline可以很方便的根据 key 从 items queue 提取item,从⽽实现 items processes集群。

Base Spider
不再使用scrapy原有的Spider类,重写的RedisSpider继承了Spider和RedisMixin这两个类,RedisMixin是用来从redis读 取url的类。当我们生成一个Spider继承RedisSpider时,调用setup_redis函数,这个函数会去连接redis数据库,然后会设置signals(信号):

当spider空闲时候的signal,会调用spider_idle函数,这个函数调用schedule_next_request函数,保证spider是一直活着的状态,并且抛出DontCloseSpider异常。

当抓到一个item时的signal,会调用item_scraped函数,这个函数会调用schedule_next_request函数,获取下一个request。

Original: https://blog.csdn.net/m0_48405781/article/details/114982668
Author: 松鼠爱吃饼干
Title: Python scrapy框架教学(五): 分布式爬虫

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/791168/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球