zoukankan      html  css  js  c++  java
  • scrapy-redis分布式爬虫

    一:基本概念

       1:什么是分布式爬虫

         --分布式爬虫,就是用多台电脑,同时运行一个爬虫文件。进行数据的爬去 

      2:原生的scrapy不能实现分布式爬取原因   

        --1:管道不能共享
        --2:调度器不能共享 

     3:使用scrapy-redis组件进行分布式爬虫,scrapy-redis专门为scrapy开发的一套组件。该组件可以使scrapy进行分布式爬虫
       --:准备工作
       --下载scrapy-redis pip install scrapy-redis
       --修改redis.conf配置文件
       --注释掉 bind 127.0.0.1 (不注释,会默认redis只能被本机链接)
       --修改 protected-mode no 关闭保护模式

    二:基于RedisCrawlSpider类的分布式爬虫

       1:创建工程

          --scrapy startproject 工程名

          --scrapy genspider -t crawl 爬虫文件名 起始url

       2:导入RedisCrawlSpider

         --修改爬虫文件基于该类的源文件

        

    # -*- coding: utf-8 -*-
    import scrapy
    from scrapy.linkextractors import LinkExtractor
    from scrapy.spiders import CrawlSpider, Rule
    from scrapy_redis import  RedisCrawlSpider
    from  redisPRO.items import RedisproItem
    #爬去糗事百科糗图的地址
    class QiubaiSpider(CrawlSpider):
        name = 'qiubai'
        # allowed_domains = ['www.baidu']
        # start_urls = ['http://www.qiushibaike.com/']
    
        #调度器名称,和start_urls 作用一样
        redis_key = 'qiubaispider'
        link = LinkExtractor(allow=r'/pic/paged+')
        rules = (
            Rule(LinkExtractor(allow=r'Items/'), callback='parse_item', follow=True),
        )
    
        def parse_item(self, response):
           div_list=response.xpath('//div[@id="content-left"]')
           for  div in div_list:
               img_url = "https"+div.xpath('.//div[@class="thumb"/a/img/@src]').extract_fist()
               item = RedisproItem()
               item['img_url']=img_url
               yield item
    

      3:修改setting.py配置文件,将管道和调度器设置成scrapy-redis组件中

          --修改管道

    #修改管道
    ITEM_PIPELINES = {
       'scrapy_redis.pipelines.RedisPipeline': 400,
    }
    

      --修改调度器

    #使用 scrapy_redis去重队列。
    DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"
    #使用 scrapy_redis调度器
    SCHEDULER = "scrapy_redis.scheduler.Scheduler"
    # 是否保持调度器队列,断点续爬
    SCHEDULER_PERSIST = True
    

      --设置redis ip和端口

    #当redis服务器不在本机,需要进行redis配置
    REDIS_HOST='192.168.10.11'
    REDIS_PORT=6379
    

      4:进入多台电脑文件目录下,执行爬虫文件

        --scrapy runspider  qiubai.py     #此时所有电脑均处于监听状态

      5:开启redis客户端,将起始的url放入队列中。(爬虫电脑监听成功后,开始运行爬虫文件,并且把结构存储到redis数据库中)

        --lpush  redis-key(对列名称)  起始url  

    三:基于RedisSpider类的分布式爬虫

        案例:基于网易新闻文字模块的爬虫

            --ua池               #对请求头进行伪装

            --代理池            #对请求ip进行批量伪装

            --selenium        #scrapy 使用 selenium模块

         1:创建工程 (略)

         2:编写爬虫文件

           a):导入RedisSpider类   from scrapy_redis.spiders import RedisSpider

           b):修改爬虫父类,继承RedisSpider类

    class WangyiSpider(RedisSpider):
    

           c):添加 redis_key属性

    redis_key='wangyi'
    

      d)编写爬虫文件逻辑

    # -*- coding: utf-8 -*-
    import scrapy
    
    from  wangyiPro.items import WangyiproItem
    from selenium import  webdriver
    from  scrapy_redis.spiders import RedisSpider
    class WangyiSpider(RedisSpider):
    
        name = 'wangyi'
        # allowed_domains = ['www.wangyi.com']
        # start_urls = ['https://news.163.com/']
        redis_key='wangyi'
        def  __init__(self):
            self.bro = webdriver.Chrome(executable='/Users/yingjianping/Desktop/chromedriver')
    
        def parse(self, response):
            lis=response.xpath('//div[@class="ns_area list"]/ul/li')
            #只爬取部分模块
            indexs=[3,4,6,7]
            li_list= [lis[index] for index in indexs]
            for  li in li_list:
                url = li.xpath('./a/@href').extract_fist()
                title =li.xpath('./a/text()').extract_fist()
                #对获取的url 进行页面解析,并获取数据信息
                yield  scrapy.Request(url=url,callback=self.secondParse,meta={'titel':title})
        def  get_content(self,response):
            item = response.meta['item']
            content_list = response.xpath('//div[@class="post_text"]/p/text()').extract()
            content = ''.join(content_list)
            item['content']=content
            yield item
    
        def  secondParse(self,response):
            #动态获取数据的,无法
            div_list=response.xpath('//div[@class="ns_area top_news clearfix"]/')
            for div  in div_list:
                 head = div.xpath('div[@class="news_title"]/h3/a/text()').extract_fist()
                 url  = div.xpath('div[@class="news_title"]/h3/a/@href').extract_fist()
                 img_url =div.xpath('./a/img/src').extract_fist()
                 tag ="".join(div.xpath('.//div[@class="new_tag"]//text()'))
                 item=WangyiproItem()
                 item['img_url']=img_url
                 item['url'] = url
                 item['tag'] = tag
                 item['head'] = head
                 item['title']=response.meta['title']
                 yield  scrapy.Request(url=url,callback=self.get_content,mate={'item':item})
    
        def  close(self):
            self.bro.quit()
    

      e):修改settings文件

             --配置redis,ip,端口,密码(有密码设置密码)

    #当redis服务器不在本机,需要进行redis配置
    REDIS_HOST='192.168.10.11'
    REDIS_PORT=6379
    #REDIS_PARAMS={'password':123456}     #有密码配置密码
    

        --配置管道文件

    ITEM_PIPELINES = {
       'scrapy_redis.pipelines.RedisPipeline': 400,
    }
    

      --配置队列

    #使用 scrapy_redis去重队列。
    DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"
    #使用 scrapy_redis调度器
    SCHEDULER = "scrapy_redis.scheduler.Scheduler"
    # 是否保持调度器队列,断点续爬
    SCHEDULER_PERSIST = True
    

      --文件执行 scrapy runspider wangyi.py

          --向redis客户端放入一个起始url

               lpush wangyi www.news.163.com

      3:selenium的使用

             a):使用场景

                --许多网站页面,部分数据是通过动态获取的,在原本的scrapy中获取的请求,不能获取页面内获取动态页面的请求

             b):使用原理

                --在下载器将下载的页面提交给spider文件中,因为获取不到动态页面数据。如果在下载器提交给spider文件过程中,通过selenium修改下载器提交结果,便可以获得完整数据。

             c):使用步骤

                 --在爬虫文件中导入webdriver类

    from selenium import  webdriver
    

             --在爬虫实列中,实列化浏览器对象

     def  __init__(self):
            self.bro = webdriver.Chrome(executable='/Users/yingjianping/Desktop/chromedriver')
    

                --close方法中关闭浏览器驱动器

        def  close(self):
            self.bro.quit()
    

           --在middlewares.py文件中 导入from scrapy.http import HtmlResponse  用于响应伪装。

               --在middlewares.py文件中重写 RedisproDownloaderMiddleware(object)方法中的proess_response()方法

    class RedisproDownloaderMiddleware(object):
    
        #可以拦截下载器传递给spider的相应对象
        #request:当前相应对象对应的请求对象
        #response:拦截到响应对象
        #spider 当前爬虫文件对应的实例化对象,   比如获取浏览器对象  spider.bro
        #没发一次请求,调用一次该方法
        def process_response(self, request, response, spider):
            #修改响应页面数据
            #1:通过selenium发送请求,去除首页
    
            if request.url not in ['https://news.163.com/']:
                spider.bro.get(url =request.url)
                #滑动页面使页面加载完全
                js_code ='windon.scrollTo(0,document.body.scrollHeight)'
                spider.pro.execute_script(js_code)
                time.sleep(3)
                page_text=spider.bro.page_sourse
                return HtmlResponse(url=spider.bro.current_url,body=page_text,enconding='utf-8')
            else:
                return response
    

      --在setting.py文件开启中间件

    DOWNLOADER_MIDDLEWARES = {
       'wangyiPro.middlewares.WangyiproDownloaderMiddleware': 543,
        
    }
    

      4:ua池的使用 

          --伪装请求头,防止被识别禁止访问

      --在middleware.py文件中导入 from scrapy.contrib.downloadermiddleware.useragent import UserAgentMiddleware

          --自定义中间件类,继承UserAgentMiddleware类,重写proess_request()方法

    import random
    
    user_agents = [
         "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; AcooBrowser; .NET CLR 1.1.4322; .NET CLR 2.0.50727)",
        "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; Acoo Browser; SLCC1; .NET CLR 2.0.50727; Media Center PC 5.0; .NET CLR 3.0.04506)",
         "Mozilla/4.0 (compatible; MSIE 7.0; AOL 9.5; AOLBuild 4337.35; Windows NT 5.1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)",
         "Mozilla/5.0 (Windows; U; MSIE 9.0; Windows NT 9.0; en-US)",
         "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0; .NET CLR 3.5.30729; .NET CLR 3.0.30729; .NET CLR 2.0.50727; Media Center PC 6.0)",
          "Mozilla/5.0 (compatible; MSIE 8.0; Windows NT 6.0; Trident/4.0; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; .NET CLR 1.0.3705; .NET CLR 1.1.4322)",
          "Mozilla/4.0 (compatible; MSIE 7.0b; Windows NT 5.2; .NET CLR 1.1.4322; .NET CLR 2.0.50727; InfoPath.2; .NET CLR 3.0.04506.30)",
          "Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN) AppleWebKit/523.15 (KHTML, like Gecko, Safari/419.3) Arora/0.3 (Change: 287 c9dfb30)",
         "Mozilla/5.0 (X11; U; Linux; en-US) AppleWebKit/527+ (KHTML, like Gecko, Safari/419.3) Arora/0.6",
         "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.2pre) Gecko/20070215 K-Ninja/2.1.1",
         "Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9) Gecko/20080705 Firefox/3.0 Kapiko/3.0",
         "Mozilla/5.0 (X11; Linux i686; U;) Gecko/20070322 Kazehakase/0.4.5",
         "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.8) Gecko Fedora/1.9.0.8-1.fc10 Kazehakase/0.5.6",
         "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.56 Safari/535.11",
         "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_3) AppleWebKit/535.20 (KHTML, like Gecko) Chrome/19.0.1036.7 Safari/535.20",
         "Opera/9.80 (Macintosh; Intel Mac OS X 10.6.8; U; fr) Presto/2.9.168 Version/11.52",
     ]
    class RandomUserAgent(UserAgentMiddleware):
        def process_request(self, request, spider):
            ua =random.choice(user_agents)
            request.headers.setdefault('User-Agent',ua)
    

        --setting.py设置开启管道 

    DOWNLOADER_MIDDLEWARES = {
       'wangyiPro.middlewares.WangyiproDownloaderMiddleware': 543,
        'wangyiPro.middlewares.RandomUserAgent': 542,
        'wangyiPro.middlewares.RandomProxy': 541,
    }
    

    5:代理池(和ua池使用方式类型)

      --自定义中间件类,继承object类,重写proess_request()方法

    #注意请求头  我这里写死了
    ip_list=[
        'http:39.134.66.72:8080',
        'http:80.68.121.217:34392'
    ]
    class RandomProxy(object):
        def process_request(self, request, spider):
            request.meta['proxy']=random.choice(ip_list)
    

      --settings.py文件中开启中间件。

     

  • 相关阅读:
    Redis序列化存储Java集合List等自定义类型
    Redis序列化存储Java集合List等自定义类型
    Unity 实现Log实时输出到屏幕或控制台上<二>
    Object-C,NumberDemo和StringDemo
    Object-C,NumberDemo和StringDemo
    Object-C,四则运算计算器
    Object-C,四则运算计算器
    HDU 3732 Ahui Writes Word
    HDU 1176 免费馅饼
    HDU 2571 命运
  • 原文地址:https://www.cnblogs.com/yingjp/p/10566729.html
Copyright © 2011-2022 走看看