• 爬虫入门(六)


    1.回顾上篇

    1.请求传参(item):
        - 应用场景:解析的数据不在同一张页面中
        - Request(callback,meta={})
    2.LOG_LEVEL  LOG_FILE
    3.下载中间件:
        - 批量拦截请求(代理ip和UA)和响应(处理页面数据)
    4.如何在scrapy使用selenium
        1.在spider的init方法中实例化一个浏览器对象
        2.在spider的closed方法中关闭浏览器对象
        3.在下载中间件类的process_response方法中接收spider中的浏览器对象
        4.处理执行相关自动化操作(发起请求,获取页面数据)
        5.实例化一个新的响应对象(from scrapy.http import HtmlResponse),且将页面数据存储到该对象中
        6.返回新的响应对象
        7.在配置文件中开启中间件
    5.如何提升scrapy爬取数据的效率:
    
    增加并发:
        默认scrapy开启的并发线程为32个,可以适当进行增加。在settings配置文件中修改CONCURRENT_REQUESTS = 100值为100,并发设置成了为100。
    
    降低日志级别:
        在运行scrapy时,会有大量日志信息的输出,为了减少CPU的使用率。可以设置log输出信息为INFO或者ERROR即可。在配置文件中编写:LOG_LEVEL = ‘INFO’
    
    禁止cookie:
        如果不是真的需要cookie,则在scrapy爬取数据时可以禁止cookie从而减少CPU的使用率,提升爬取效率。在配置文件中编写:COOKIES_ENABLED = False
    
    禁止重试:
        对失败的HTTP进行重新请求(重试)会减慢爬取速度,因此可以禁止重试。在配置文件中编写:RETRY_ENABLED = False
    
    减少下载超时:
        如果对一个非常慢的链接进行爬取,减少下载超时可以能让卡住的链接快速被放弃,从而提升效率。在配置文件中进行编写:DOWNLOAD_TIMEOUT = 10 超时时间为10s
    提升scrapy爬取数据的效率

    2.使用scrapy自带的分页处理

    # 创建spider爬虫文件命令
    scrapy genspider -t crawl filename url
     1 # -*- coding: utf-8 -*-
     2 import scrapy
     3 from scrapy.linkextractors import LinkExtractor
     4 from scrapy.spiders import CrawlSpider, Rule
     5 
     6 
     7 class ChoutiSpider(CrawlSpider):
     8     # name = 'chouti'
     9     # # allowed_domains = ['www.xxx.com']
    10     # start_urls = ['https://dig.chouti.com/r/scoff/hot/1']
    11     # # 连接提取器
    12     # # allow表示的就是连接提取器提取连接的规则(正则)
    13     # link = LinkExtractor(allow=r'/r/scoff/hot/d+')
    14     #
    15     # rules = (
    16     #     # 规则解析器:将连接提取器提取到的连接所对应的页面数据进行指定形式的解析
    17     #     Rule(link, callback='parse_item', follow=True),
    18     #     # 让连接提取器继续作用到连接提取器提取到的连接所对应的页面中
    19     # )
    20     #
    21     # def parse_item(self, response):
    22     #     print(response)
    23 
    24     name = 'qiushi'
    25     # allowed_domains = ['www.xxx.com']
    26     start_urls = ['https://www.qiushibaike.com/pic/']
    27     # 连接提取器
    28     # allow表示的就是连接提取器提取连接的规则(正则)
    29     link = LinkExtractor(allow=r'/pic/page/d+?s=d+')
    30     link1 = LinkExtractor(allow=r'/pic/$')
    31     rules = (
    32         # 规则解析器:将连接提取器提取到的连接所对应的页面数据进行指定形式的解析
    33         Rule(link, callback='parse_item', follow=True),
    34         # 让连接提取器继续作用到连接提取器提取到的连接所对应的页面中
    35         Rule(link1, callback='parse_item', follow=True),
    36     )
    37 
    38     def parse_item(self, response):
    39         print(response)
    spider

    3.分布式爬虫

    分布式爬虫实现流程
    1.环境安装:pip install scrapy-redis
    2.创建工程
    3.创建爬虫文件:RedisCrawlSpider  RedisSpider
        - scrapy genspider -t crawl xxx www.xxx.com
    4.对爬虫文件中的相关属性进行修改:
        - 导报:from scrapy_redis.spiders import RedisCrawlSpider
        - 将当前爬虫文件的父类设置成RedisCrawlSpider
        - 将起始url列表替换成redis_key = 'xxx'(调度器队列的名称)
    5.在配置文件中进行配置:
        - 使用组件中封装好的可以被共享的管道类:
            ITEM_PIPELINES = {
                'scrapy_redis.pipelines.RedisPipeline': 400
                }
        - 配置调度器(使用组件中封装好的可以被共享的调度器)
            # 增加了一个去重容器类的配置, 作用使用Redis的set集合来存储请求的指纹数据, 从而实现请求去重的持久化
            DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"
            # 使用scrapy-redis组件自己的调度器
            SCHEDULER = "scrapy_redis.scheduler.Scheduler"
            # 配置调度器是否要持久化, 也就是当爬虫结束了, 要不要清空Redis中请求队列和去重指纹的set。如果是True,
             就表示要持久化存储, 就不清空数据, 否则清空数据
            SCHEDULER_PERSIST = True
    
         - 指定存储数据的redis:
            REDIS_HOST = 'redis服务的ip地址'
            REDIS_PORT = 6379
    
         - 配置redis数据库的配置文件
            - 取消保护模式:protected-mode no
            - bind绑定: #bind 127.0.0.1
    
         - 启动redis
    
    6.执行分布式程序
        scrapy runspider xxx.py(文件的绝对路径)
    
    7.向调度器队列中仍入一个起始url:
        在redis-cli中执行:
        lpush redis_key url(起始url)

    settings

     1 ITEM_PIPELINES = {
     2     'scrapy_redis.pipelines.RedisPipeline': 400
     3 }
     4 # 增加了一个去重容器类,作用使用Redis的set集合来存储请求的指纹数据,从而实现请求去重的持久化
     5 DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"
     6 # 使用scrapy-redis组件自己的调度器
     7 SCHEDULER = "scrapy_redis.scheduler.Scheduler"
     8 # 配置调度器是否要持久化,也就是当爬虫结束了,要不要清空redis中请求队列和去重指纹的set。如果是true,就表示要持久化,就不清空,否则清空数据。
     9 SCHEDULER_PERSIST = True  #数据指纹
    10 
    11 REDIS_HOST = '127.0.0.1'
    12 REDIS_PORT = 6379
    View Code

    spider

     1 # -*- coding: utf-8 -*-
     2 import scrapy
     3 from scrapy.linkextractors import LinkExtractor
     4 from scrapy.spiders import CrawlSpider, Rule
     5 from scrapy_redis.spiders import RedisCrawlSpider
     6 from redisChoutiPro.items import RedischoutiproItem
     7 
     8 
     9 class ChoutiSpider(RedisCrawlSpider):
    10     name = 'chouti'
    11     # allowed_domains = ['www.xxx.com']
    12     # start_urls = ['http://www.xxx.com/']
    13     redis_key = 'chouti'  # 调度器队列的名称
    14     rules = (
    15         Rule(LinkExtractor(allow=r'/all/hot/recent/d+'), callback='parse_item', follow=True),
    16     )
    17 
    18     def parse_item(self, response):
    19         div_list = response.xpath('//div[@class="item"]')
    20         for div in div_list:
    21             title = div.xpath('./div[4]/div[1]/a/text()').extract_first()
    22             autor = div.xpath('./div[4]/div[2]/a[4]/b/text()').extract_first()
    23 
    24             item = RedischoutiproItem()
    25             item['title'] = title
    26             item['author'] = autor
    27 
    28             yield item
    View Code

    4.增量式的常见两种情况

    1.处理url地址的重复

    spider

     1 # -*- coding: utf-8 -*-
     2 import scrapy
     3 from scrapy.linkextractors import LinkExtractor
     4 from scrapy.spiders import CrawlSpider, Rule
     5 from redis import Redis
     6 from increment1_Pro.items import Increment1ProItem
     7 
     8 
     9 class MovieSpider(CrawlSpider):
    10     name = 'movie'
    11     # allowed_domains = ['www.123.com']
    12     start_urls = ['https://www.4567tv.tv/index.php/vod/show/id/7.html']
    13 
    14     rules = (
    15         Rule(LinkExtractor(allow=r'/index.php/vod/show/id/7/page/d+.html'), callback='parse_item', follow=True),
    16     )
    17 
    18     def parse_item(self, response):
    19         conn = Redis(host='127.0.0.1', port=6379)
    20         detail_url_list = ['https://www.4567tv.tv' + i for i in response.xpath('//li[@class="col-md-6 col-sm-4 col-xs-3"]/div/a/@href').extract()]
    21         for url in detail_url_list:
    22             # ex == 1:set中没有存储url
    23             ex = conn.sadd('moves_url', url)
    24             if ex == 1:
    25                 yield scrapy.Request(url=url, callback=self.parse_detail)
    26             else:
    27                 print('网站没有更新数据,暂无新数据可爬!')
    28 
    29     def parse_detail(self, response):
    30         item = Increment1ProItem()
    31         item['name'] = response.xpath('/html/body/div[1]/div/div/div/div[2]/h1/text()').extract_first()
    32         item['actor'] = response.xpath('/html/body/div[1]/div/div/div/div[2]/p[3]/a/text()').extract_first()
    33 
    34         yield item
    View Code

    pipelines

     1 # -*- coding: utf-8 -*-
     2 
     3 # Define your item pipelines here
     4 #
     5 # Don't forget to add your pipeline to the ITEM_PIPELINES setting
     6 # See: https://doc.scrapy.org/en/latest/topics/item-pipeline.html
     7 
     8 from redis import Redis
     9 
    10 class Increment1ProPipeline(object):
    11     conn = None
    12 
    13     def open_spider(self, spider):
    14         self.conn = Redis(host='127.0.0.1', port=6379)
    15 
    16     def process_item(self, item, spider):
    17         dic = {
    18             'name': item['name'],
    19             'actor': item['actor']
    20         }
    21         print('有新数据被爬取到,正在入库......')
    22         self.conn.lpush('movie_data', item)
    23         return item
    View Code

    2.处理爬取数据内容重复

    spider

     1 # -*- coding: utf-8 -*-
     2 import scrapy
     3 import hashlib
     4 from scrapy.linkextractors import LinkExtractor
     5 from scrapy.spiders import CrawlSpider, Rule
     6 from redis import Redis
     7 from increment2_Pro.items import Increment2ProItem
     8 
     9 
    10 class QiubaiSpider(CrawlSpider):
    11     name = 'qiubai'
    12     # allowed_domains = ['www.123.com']
    13     start_urls = ['https://www.qiushibaike.com/text/']
    14 
    15     rules = (
    16         Rule(LinkExtractor(allow=r'/text/page/d+/'), callback='parse_item', follow=True),
    17     )
    18 
    19     def parse_item(self, response):
    20         div_list = response.xpath('//div[@class="article block untagged mb15 typs_hot"]')
    21         conn = Redis(host='127.0.0.1', port=6379)
    22         for div in div_list:
    23             item = Increment2ProItem()
    24             item['content'] = div.xpath('./a[1]/div/span//text()').extract()
    25             item['content'] = ''.join(item['content'])
    26             item['author'] = div.xpath('./div[1]/a[2]/h2/text() | ./div[1]/span[2]/h2/text()').extract_first()
    27 
    28             source = item['author'] + item['content']
    29             # 自己定制一种形式的数据指纹
    30             hash_value = hashlib.sha256(source.encode()).hexdigest()
    31 
    32             ex = conn.sadd('qiubai_hash', hash_value)
    33             if ex == 1:
    34                 yield item
    35             else:
    36                 print('没有更新数据!')
    View Code

    pipelines

     1 # -*- coding: utf-8 -*-
     2 
     3 # Define your item pipelines here
     4 #
     5 # Don't forget to add your pipeline to the ITEM_PIPELINES setting
     6 # See: https://doc.scrapy.org/en/latest/topics/item-pipeline.html
     7 from redis import Redis
     8 
     9 
    10 class Increment2ProPipeline(object):
    11     conn = None
    12 
    13     def open_spider(self, spider):
    14         self.conn = Redis(host='127.0.0.1', port=6379, encoding='utf-8')
    15 
    16     def process_item(self, item, spider):
    17         dic = {
    18             'author': item['author'],
    19             'content': item['content']
    20         }
    21 
    22         self.conn.lpush('aiubaiData', dic)
    23         print('爬取到一条数据,正在入库!')
    24         return item
    View Code
  • 相关阅读:
    【STM32H7的DSP教程】第13章 DSP快速计算函数-三角函数和平方根
    【STM32F429的DSP教程】第13章 DSP快速计算函数-三角函数和平方根
    【STM32F407的DSP教程】第13章 DSP快速计算函数-三角函数和平方根
    分布式锁--redis(单节点)
    Lock
    Condition
    Synchronized
    并发线程池
    多线程实现原理
    多线程基础
  • 原文地址:https://www.cnblogs.com/qq849784670/p/10479255.html
Copyright © 2020-2023  润新知