zoukankan      html  css  js  c++  java
  • scrapy入门(四)分布式和增量式

    一. 分布式

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

    2. scrapy + scrapy_redis实现分布式

      scrapy_redis组件的功能 :

      • 提供可被共享的调度器和管道
      • 数据只能存储到redis数据库中
    3. 实现流程

      1. 修改源文件
      #以创建CrawlSpider为例
      #导包
      from scrapy_redis.spiders import RedisCrawlSpider
      #修改爬虫类的父类
      class FbsSpider(RedisCrawlSpider):
          #注释掉allow_domains和start_urls,分布式不推荐使用start_urls
          #添加新属性
          redis_key ='fbsQueue'#表示的是可以被共享的调度器队列的名称,将起始url直接放到调度器中
      
      1. settings文件的配置
      ITEM_PIPELINES = {
          'scrapy_redis.pipelines.RedisPipeline':300
      }
      #确保所有的爬虫通过Redis去重
      DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"
      #启用Redis调度存储请求队列
      SCHEDULER = "scrapy_redis.scheduler.Scheduler"
      #不清除Redis队列,起到记忆功能
      #例如隔几天后重新爬取同一个网站,设置为True则之前爬取过的数据不再爬取
      SCHEDULER_PERSIST = True
      
      #指定redis数据库
      #指定连接到redis时使用的端口和地址(可选)
      REDIS_HOST = '指定一个ip地址'
      REDIS_PORT = 6379
      
      1. 对redis数据库的配置文件进行操作(redis.windows.conf)

        • 关闭默认绑定 : 56 Line : #bind 127.0.0.1
        • 关闭保护模式 :75 Line : protect-mode no
      2. 携带配置文件启动redis服务端, 再启动客户端

        • redis-server.exe redis.windows.conf
        • redis-cli
      3. 在pycharm中启动程序
        scrapy run spider fbs.py #fbs是自定义爬虫名

        之后程序会等待我们进行redis数据库的操作, 才会继续进行

      4. 向调度器的队列中扔入一个起始的url :

        启动redis客户端,输入lpush fbsQueue "起始url"

    二. 增量式

    核心机制: 对详情页的url去重. redis的set实现去重

    原理实现过程:

    • 需要两张表, 一张保存数据源文件, 一份保存数据文件生成的数据指纹
    • 每次先将爬取到的文件生成一份对应的数据指纹,
      • 如果已经存在数据指纹库中, 则不需要向管道提交,
      • 否则保存数据指纹和原文件
    #python源文件
    from redis import Redis
    
    class ZlsSpider(CrawlSpider):
        #将连接对象作为ZlsSpider类的一个属性
        conn = Redis(host = '127.0.0.1',port = 6379)
        pass
    
    def parse_item(self,response):
        #...
        detail_url = li.xpath('xxxxxxx')
        #将解析得到的url和redis数据库中的表作比较
        #对于不需要深度爬取的页面,可以将要爬取的数据文件拼成一个字符串,然后放入到hashlib中生成一个专属source_id,就相当于url,以后爬取的时候同样判断这个source_id是否在对应的data_id表中
        #source = item['author'] + item['content']
        #source_id =hashlib.sha256(source.encode()).hexdigest()
        #ex = self.conn.sadd('data_id',source_id)
        
        #sadd()功能:如果url存在则不向表中添加数据并返回0,不存在则向表中添加并返回1
        ex = self.conn.sadd('urls_id',detail_url)#urls_id为数据库记录url是否爬取过的表
        if ex == 1 :
            #手动发送请求
            yield scrapy.Request(detail_url,callback=self.parse_detail,meta={'item':item})
    def parse_detail(self,response):
        content = response.xpath('xxxxxxxxxx').extract_first()
        
        item = response.meta['item']
        #item对象在前面的for循环中创建,保证每次循环请求不同的url时生成一个item对象
        item['content'] =content
        
        #将item对象传递给管道
        yield item
    
    #pipelines文件中
    def process_item(self, item, spider):
        #接受爬虫类的conn
        conn = spider.conn
        conn.lpush('detail_data',item) #detail_data用来保存爬取的数据信息
       	return item
    

    三. 反爬机制总结

    • robots
    • UA伪装
    • 验证码
    • 代理
    • cookie
    • 动态变化的请求参数
    • js加密
    • js混淆
    • 图片懒加载
    • 动态数据的捕获
    • selenium :规避检测
  • 相关阅读:
    node异步转同步(循环)
    三级省市区PCASClass.js插件
    微信公众号基础总结(待更新)
    ES6详解
    webpack配置
    高性能 CSS3 动画
    github上传口令
    纯css3 实现3D轮播图
    优美的js代码,拿去玩~
    关于列举属性用点还是用【】
  • 原文地址:https://www.cnblogs.com/yimeisuren/p/12419812.html
Copyright © 2011-2022 走看看