爬虫 分布式和增量式

分布式

需要搭建一个分布式的机群,在机群的每一台电脑中执行同一组程序,让其对某一个网站的数据进行联合分布爬取。

  • 原生的scrapy不能实现分布式的原因

    • 因为调度器不可以被共享
    • 管道不可以被共享
  • 如何实现分布式

    • scrapy+scrapy_redis实现分布式
  • scrapy_redis组件作用

    • 可以提供可被共享的调度器和管道
    • 特性:数据只可以存储到redis数据库

  • 分布式的实现流程

    • pip instal scrapy-redis
    • 创建工程
    • cd到工程目录
    • 创建爬虫文件(a.创建基于Spider的爬虫文件 b.创建CrawlSpider的爬虫文件)
    • 修改爬虫类
      • 倒包:from scrapy_redis.spiders import RedisCrawlSpider(根据创建类型选择)
      • 修改当前爬虫类的父类为 RedisCrawlSpider
      • allowed_domains和start_urls删除
      • 添加一个新属性:redis_key = ‘fbsQueue’ 表示可以被共享的调度器队列的名称
      • 编写爬虫类的其他操作(常规操作)
    • settings配置文件的配置
      • UA伪装

      • Robots

      • 管道的指定:ITEM_PIPELINES = {‘scrpay_redis.pipelines.RedisPipeline’: 400}

      • 指定调度器:

        • DUPEFILTER_CLASS = “scrapy_redis.dupefilter.RFPDupeFilter” 使用scrapy-redis组件的去重队列
        • SCHEDULER = “scrapy_redis.scheduler.Scheduler” 使用scrapy-redis组件自己的调度区
        • SCHEDULER_PERSIST = True 增量式使用,也就是当爬虫结束,要不要清楚redis中请求队列和去重,True为不清除,持久化存储
      • 指定redis数据库

        • REDIS_HOST = ‘redis服务的ip地址’
        • REDIS_PORT = 6379
        • REDIS_ENCODING = ‘utf-8’
      • redis的配置文件进行配置redis.windows.conf:

        • 关闭默认绑定:56行 #bind 127.0.0.1
        • 关闭保护模式:75行 protected-mode no
      • 启动redis服务端和客户端

        • redis-server.ext redis.windows.conf
        • redis-cli
      • 启动程序

        • scrapy runspider xxx.py
      • 向调度器的队列中扔入一个起始的url

        • 队列是存在于redis中
        • 开启redis的客户端:lpush fbsQueue http://wz.sun0769.com/political/index/politicsNewest?id=1&page=

增量式

用于检测网站数据更新的情况。核心机制:去重。redis的set实现去重


爬取4567电影名称和电影详情——深度爬取

import scrapy
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule
from redis import Redis
from movie_zls.items import MovieZlsItem


class MovieSpider(CrawlSpider):
    conn = Redis(host='127.0.0.1', port=6379)
    name = 'movie'
    # allowed_domains = ['www.xxx.com']
    start_urls = ['https://www.4567kan.com/frim/index6.html']

    rules = (
        Rule(LinkExtractor(allow=r'frim/index6-\d.html'), callback='parse_item', follow=True),
    )

    def parse_item(self, response):
        li_list = response.xpath('/html/body/div[1]/div/div/div/div[2]/ul/li')
        for li in li_list:
            name = li.xpath('./div/a/@title').extract_first()
            item = MovieZlsItem()
            item['name'] = name
            detail_url = 'https://www.4567kan.com' + li.xpath('./div/a/@href').extract_first()
            # 记录爬过的电影详情页的url。ex=0插入失败,ex=1插入成功
            ex = self.conn.sadd('movie_detail_urls', detail_url)
            if ex == 1:
                print('捕获到新数据')
                yield scrapy.Request(detail_url, callback=self.parse_detail, meta={'item': item})
            else:
                print('无数据更新')

    def parse_detail(self, response):
        desc = response.xpath('/html/body/div[1]/div/div/div/div[2]/p[5]/span[2]/text()').extract_first()
        item = response['item']
        item['desc'] = desc
        yield desc
class MovieZlsPipeline:
    def process_item(self, item, spider):
        conn = spider.conn
        conn.lpush('movieData', item)
        return item

糗事百科爬取文章内容和标题——不用深度爬取
爬取标题和文章,都在同一个页面中就可爬取到,添加数据指纹

            #将解析到的数据值生成一个唯一的标识进行redis存储
            source = item['author']+item['content']
            source_id = hashlib.sha256(source.encode()).hexdigest()
            #将解析内容的唯一表示存储到redis的data_id中
            ex = self.conn.sadd('data_id',source_id)

            if ex == 1:
                print('该条数据没有爬取过,可以爬取......')
                yield item
            else:
                print('该条数据已经爬取过了,不需要再次爬取了!!!')

你可能感兴趣的:(python,#,python爬虫)