【Scrapy框架基于scrapy-redis实现分布式爬虫】 -- 2019-08-07 10:14:58

徘徊边缘 提交于 2019-11-25 19:47:38

原创: http://106.13.73.98/__/26/

Scrapy框架无法自己实现分布式,原因有二

  1. 多台机器上部署的Scrapy各自拥有各自的调度器,这样就使得多台机器无法分配 start_urls 列表中的url,即多台机器无法共享同一个调度器
  2. 多台机器爬取到的数据无法通过同一个管道进行统一的持久化存储,即多台机器无法共享同一个管道
    ___

基于 scrapy-redis 组件的分布式爬虫

安装 :pip install scrapy-redis

scrapy-redis组件为我们封装好了可以共享给多台机器的调度器和管道,我们可以直接使用它来实现分布式爬取数据。

scrapy-redis 常见键名

  1. 爬虫名:items list类型,保存爬虫获取到的数据,item对象,内容为JSON字符串。
  2. 爬虫名:dupefilter set类型,用于对爬虫访问过的url进行去重,内容是40个字符的url的hash字符串。
  3. 爬虫名:start_urls list类型,默认的共享调度器名称,可指定为其它名称,用于获取spider启动时爬取的起始url,需手动写入起始url。
  4. 爬虫名:requests zset类型,用于scheduler调度处理 requests 内容是 request 对象的序列化字符串。

使用步骤

  1. 修改爬虫类的父类,如果原始爬虫文件时基于 Spider 的,则应该将父类修改为 RedisSpider,如果原始爬虫文件时基于 CrawlSpider 的,则应该将其父类修改成 RedisCrawlSpider
  2. 删掉 start_urls 列表,并加入 redis_key 属性,该属性的值为scrapy-redis组件中的调度器队列名称。
  3. 在配置文件中进行相关配置来开启使用scrapy-redis组件中封装好的管道,相关配置如下。

相关配置

# 使用scrapy-redis组件中封装好的管道,直接将数据存入Redis中,不再需要pipelines文件
ITEM_PIPELINES = {
    'scrapy_redis.pipelines.RedisPipeline': 100
}

# 使用scrapy-redis组件的去重队列,不再使用scrapy默认的去重方式
DUPEFILTER_CLASS = 'scrapy_redis.dupefilter.RFPDupeFilter'

# 使用scrapy-redis组件的调度器,不使用默认的调度器
SCHEDULER = 'scrapy_redis.scheduler.Scheduler'

# 允许暂停,redis请求记录不会丢失
SCHEDULER_PERSIST = True
# 即:配置调度器是否允许持久化,即爬取结束后 是否清空Redis中的请求队列和去重指纹set


"""请求队列形式"""
# 1.按优先级(默认)
# SCHEDULER_QUEUE_CLASS = "scrapy_redis.queue.SpiderPriorityQueue"
# 2.队列形式,请求先进先出
#SCHEDULER_QUEUE_CLASS = "scrapy_redis.queue.SpiderQueue"
# 3.栈形式,请求先进后出
#SCHEDULER_QUEUE_CLASS = "scrapy_redis.queue.SpiderStack"


"""连接Redis配置"""
REDIS_HOST = '9.0.0.1'  # Redis监听地址
REDIS_PORT = 6380  # Redis监听端口
REDIS_ENCODING = 'utf-8'  # 编码

# 如果你的Redis设置了连接密码:
# REDIS_PARAMS = {'password': 'Redis密码'}

开始使用

第一种,基于 RedisSpider 的分布式爬虫:

# -*- coding: utf-8 -*-
import scrapy
from blog.items import  BlogItem
from scrapy_redis.spiders import RedisSpider  # pip install scrapy-redis


class Blog01Spider(RedisSpider):  # 更改继承类为RedisSpider
    name = 'blog01'

    # 删掉起始url列表,使用下面的redis_key
    # start_urls = ['http://www.xxx.com/']

    # 指定共享的调度器队列名称(起始url列表)
    redis_key = 'cmda'  # cmda:中国医师协会简称
    # 如果你不指定此属性,则默认的共享调度器队列名称为:blog01:start_urls

    present_page = 1  # 用于标识当前页面
    max_page = 1000  # 你想爬取多少页数据
    url = 'http://db.pharmcube.com/database/cfda/detail/cfda_cn_instrument/%d'  # 用于计算页面的url


    def parse(self, response):

        # 解析每一个页面
        item = BlogItem()
        item['num'] = response.xpath('/html/body/div/table/tbody/tr[1]/td[2]/text()').extract_first()  # 注册证编号
        item['company_name'] = response.xpath('//html/body/div/table/tbody/tr[2]/td[2]/text()').extract_first()  # 注册人名称
        item['company_address'] = response.xpath('/html/body/div/table/tbody/tr[3]/td[2]/text()').extract_first()  # 注册人住所
        
        yield item
        # 在items文件中写好要保存的字段
        # 这里会将item对象提交给scrapi-redis组件的管道

        # 下面开始递归爬取所有页面
        urls = []
        if self.present_page <= self.max_page:
            self.present_page += 1
            url = format(self.url % self.present_page)
            yield scrapy.Request(url, callback=self.parse)

# 注意修改你的配置文件,写入相关的配置

第二种,基于 RedisCrawlSpider 的分布式爬虫:

# -*- coding: utf-8 -*-
import scrapy
from blog.items import ChoutiProItem
from scrapy_redis.spiders import RedisCrawlSpider  # pip install scrapy-redis
from scrapy.linkextractors import LinkExtractor
# LinkExtractor:链接提取器,用于提取起始url页面中符合匹配规则的链接
from scrapy.spiders import CrawlSpider, Rule
# CrawlSpider:是Spider的一个子类,除了继承了Spider的特性和功能外,还派生了自己独有的强大特性和功能
# Rule:规则解析器,用于将链接提取器提取到的链接对应的页面源码数据根据指定的解析方法(回调函数)进行解析


class Blog02Spider(RedisCrawlSpider):  # 更改继承类为RedisCrawlSpider
    name = 'blog02'

    # allowed_domains = ['www.xxx.com']

    # 删掉起始url列表,使用下面的redis_key
    # start_urls = ['http://www.xxx.com/']

    # 指定共享的调度器队列名称(共享的起始url列表)
    redis_key = 'chouti' # https://dig.chouti.com/r/scoff/hot
    # 如果你不指指定此属性,则默认的共享调度器队列名称为:blog01:start_urls

    # 定义链接提取规则
    link = LinkExtractor(allow=r'/r/scoff/hot/\d+')

    # 在这里定义规则解析器
    rules = (
        Rule(link, callback='parse_item', follow=True),
    )

    def parse_item(self, response):
        div_list = response.xpath('//div[@id="content-list"]/div')
        for div in div_list:
            item = ChoutiProItem()
            item['title'] = div.xpath('.//div[@class="part1"]/a/text()').extract_first()  # 段子标题
            item['author'] = div.xpath('.//div[@class="part2"]/a[4]/b/text()').extract_first()  # 段子内容
            print(item.__dict__)

            yield item
            # 在items文件中写好要保存的字段
            # 这里会将item对象提交给scrapi-redis组件的管道

# 注意修改你的配置文件,写入相关的配置

准备就绪后,启动redis服务器和客户端,在所有爬虫机器上执行命令 scrapy runspider 爬虫文件路径 运行爬虫程序,然后在redis客户端中执行 lpush redis_key属性值 起始url 来传入起始url。此时,所有爬虫程序将开始工作。

成功爬取数据后,你可以在redis客户端中使用 smembers 爬虫名:dupefilter 来查看爬取到的数据。
___

所有渴望别人理解的行为,都是弱者的行为。人的强大,第一步 要学会孤独,第二步 要学会不被理解,第三步 就是用结果去碾压。加油!

原创: http://106.13.73.98/__/26/

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!