刘沙河 刘沙河
首页
  • Go语言基础

    • 数据类型
    • 反射
    • Go指针
  • Go语言进阶

    • go泛型
    • go条件编译
    • cgo教程
    • Go协程调度原理及GPM模型
    • Go内存管理
    • Go垃圾回收机制
    • Go语言内存对齐
  • Go语言实现原理

    • channel 实现原理
    • slice 实现原理
    • map 实现原理
    • sync.Mutex 实现原理
    • 乐观锁CAS 实现原理
    • singlefight 实现原理
  • gin框架

    • gin中间件原理
    • gin路由原理
  • gorm

    • GORM介绍和使用
    • GORM_CURD操作指南
  • go测试

    • benchmark基准测试
    • pprof 性能分析
  • python进阶

    • Numpy&Pandas
    • celery分布式任务队列
  • Django

    • Django 常见命令
    • middleware中间件
    • Django缓存系统
    • Django信号系统
    • Django REST Framework
  • Flask

    • Flask基础知识总结
    • Flask-SQLAlchemy
  • 爬虫

    • aiohttp
    • scrapy框架
  • Mysql

    • Mysql存储引擎和索引
    • MySQL主从复制
    • Mysql读写分离
    • 数据库分库分表
    • Mysql锁
    • Mysql事务和MVCC原理
    • 分库分表带来的读扩散问题
  • Redis

    • redis基础和数据类型
    • redis主从架构
    • redis哨兵架构
    • redis集群模式
    • 如何保证缓存和数据库双写一致
    • redis底层数据结构
    • redis分布式锁
  • Elasticsearch

    • es基本概念
    • es基础语法
    • es倒排索引
  • etcd

    • Go操作etcd
    • Raft原理
    • etcd分布式锁
  • kafka

    • 消息队列MQ总结
    • kafka 概述及原理
    • kafka 消费问题记录
    • 零拷贝技术
    • kafka分区规范
  • RabbitMQ

    • rabbitMQ基础
    • Go操作rabbitmq
  • RocketMQ

    • 可靠消息队列 rocketMQ
  • Http&Https

    • http&https
    • TCP和UDP
    • Ping 原理
  • RPC

    • RPC初识
    • grpc初识和实现
  • gRPC

    • grpc 初识
    • grpc 上下文 metadata
    • grpc 健康检查
    • grpc keepalive
    • grpc 命名解析
    • grpc 中间件&拦截器
    • grpc 负载均衡
    • grpc 身份认证
    • grpc 超时重试
    • grpc 链路追踪
    • grpc-gw将gRPC转RESTfu api
    • grpc-gw自定义选项
  • protobuf

    • protobuf 进阶
    • protobuf 编码原理
  • Docker

    • Docker基础
    • Docker常用命令
    • Dockerfile
    • Docker-Compose
    • Docker多阶段构建
    • Docker Config 教程
    • Docker Swarm 教程
    • Docker Stack 教程
    • Docker Buildx 教程
  • k8s

    • k8s 基础概念
    • k8s 集群架构
    • k8s 工作负载
    • Pod 网络
    • Service 网络
    • 外部接入网络
    • 一张图搞懂k8s各种pod
    • k8s 存储抽象
    • mac快速启动k8s
    • 自制申威架构k8s-reloader
  • go-kit

    • go-kit初识
    • go-kit启动http服务
    • go-kit集成gin启动服务
    • go-kit集成grpc和protobuf
    • go-kit中间件
    • go-kit服务注册发现与负载均衡
    • go-kit限流和熔断
    • go-kit链路追踪
    • go-kit集成Prometheus
  • 设计模式

    • 初识设计模式
    • 创建型模式
    • 结构型模式
    • 行为模式
  • 数据结构

    • 时间轮
    • 堆、双向链表、环形队列
    • 队列:优先队列
    • 队列:延迟队列
  • 算法

    • 递归算法
    • 枚举算法
    • 动态规划
    • 回溯算法
    • 分治算法
    • 贪心算法
    • LRU和LFU
    • 一致性哈希

花开半夏,半夏花开
首页
  • Go语言基础

    • 数据类型
    • 反射
    • Go指针
  • Go语言进阶

    • go泛型
    • go条件编译
    • cgo教程
    • Go协程调度原理及GPM模型
    • Go内存管理
    • Go垃圾回收机制
    • Go语言内存对齐
  • Go语言实现原理

    • channel 实现原理
    • slice 实现原理
    • map 实现原理
    • sync.Mutex 实现原理
    • 乐观锁CAS 实现原理
    • singlefight 实现原理
  • gin框架

    • gin中间件原理
    • gin路由原理
  • gorm

    • GORM介绍和使用
    • GORM_CURD操作指南
  • go测试

    • benchmark基准测试
    • pprof 性能分析
  • python进阶

    • Numpy&Pandas
    • celery分布式任务队列
  • Django

    • Django 常见命令
    • middleware中间件
    • Django缓存系统
    • Django信号系统
    • Django REST Framework
  • Flask

    • Flask基础知识总结
    • Flask-SQLAlchemy
  • 爬虫

    • aiohttp
    • scrapy框架
  • Mysql

    • Mysql存储引擎和索引
    • MySQL主从复制
    • Mysql读写分离
    • 数据库分库分表
    • Mysql锁
    • Mysql事务和MVCC原理
    • 分库分表带来的读扩散问题
  • Redis

    • redis基础和数据类型
    • redis主从架构
    • redis哨兵架构
    • redis集群模式
    • 如何保证缓存和数据库双写一致
    • redis底层数据结构
    • redis分布式锁
  • Elasticsearch

    • es基本概念
    • es基础语法
    • es倒排索引
  • etcd

    • Go操作etcd
    • Raft原理
    • etcd分布式锁
  • kafka

    • 消息队列MQ总结
    • kafka 概述及原理
    • kafka 消费问题记录
    • 零拷贝技术
    • kafka分区规范
  • RabbitMQ

    • rabbitMQ基础
    • Go操作rabbitmq
  • RocketMQ

    • 可靠消息队列 rocketMQ
  • Http&Https

    • http&https
    • TCP和UDP
    • Ping 原理
  • RPC

    • RPC初识
    • grpc初识和实现
  • gRPC

    • grpc 初识
    • grpc 上下文 metadata
    • grpc 健康检查
    • grpc keepalive
    • grpc 命名解析
    • grpc 中间件&拦截器
    • grpc 负载均衡
    • grpc 身份认证
    • grpc 超时重试
    • grpc 链路追踪
    • grpc-gw将gRPC转RESTfu api
    • grpc-gw自定义选项
  • protobuf

    • protobuf 进阶
    • protobuf 编码原理
  • Docker

    • Docker基础
    • Docker常用命令
    • Dockerfile
    • Docker-Compose
    • Docker多阶段构建
    • Docker Config 教程
    • Docker Swarm 教程
    • Docker Stack 教程
    • Docker Buildx 教程
  • k8s

    • k8s 基础概念
    • k8s 集群架构
    • k8s 工作负载
    • Pod 网络
    • Service 网络
    • 外部接入网络
    • 一张图搞懂k8s各种pod
    • k8s 存储抽象
    • mac快速启动k8s
    • 自制申威架构k8s-reloader
  • go-kit

    • go-kit初识
    • go-kit启动http服务
    • go-kit集成gin启动服务
    • go-kit集成grpc和protobuf
    • go-kit中间件
    • go-kit服务注册发现与负载均衡
    • go-kit限流和熔断
    • go-kit链路追踪
    • go-kit集成Prometheus
  • 设计模式

    • 初识设计模式
    • 创建型模式
    • 结构型模式
    • 行为模式
  • 数据结构

    • 时间轮
    • 堆、双向链表、环形队列
    • 队列:优先队列
    • 队列:延迟队列
  • 算法

    • 递归算法
    • 枚举算法
    • 动态规划
    • 回溯算法
    • 分治算法
    • 贪心算法
    • LRU和LFU
    • 一致性哈希
  • Python基础

  • Python进阶

  • Python并发编程

  • Django

  • Flask

  • 爬虫

    • 认识爬虫& request
    • bs4 和 xpath
    • 代理-cookie-验证码识别-模拟登录
    • 线程池-协程-aiohttp-selenium
    • 移动端数据爬取-scrapy框架
    • scrapy框架-媒体文件爬取-middleware
    • 基于CrawlSpider全栈数据爬取,分布式爬虫
      • 1.基于CrawlSpider全栈数据爬取
        • 使用流程
      • 2.分布式爬虫
      • 3.增量式爬虫
  • Python
  • 爬虫
bigox
2021-03-22
目录

基于CrawlSpider全栈数据爬取,分布式爬虫

# 1.基于CrawlSpider全栈数据爬取

  • CrawlSpider就是爬虫类Spider的一个子类

# 使用流程

  1. 创建scrapy工程:scrapy startproject projectName

  2. 创建一个基于CrawlSpider的一个爬虫文件 :scrapy genspider -t crawl spider_name www.xxx.com

  3. 构造链接提取器和规则解析器

    • 链接提取器:

      • 作用:可以根据指定的规则进行指定连接的提取
      • 提取的规则: allow = "正则表达式"
      • 会先在全局匹配所有的url,然后根据参数allow的规则匹配需要的链接
    • 规则解析器

      • 作用:获取链接提取器提取到的链接,对其进行请求发送,根据指定的规则对请求道的页面源码数据进行数据解析.-
      • fllow = True 参数的作用: 将链接提取器继续作用到链接提取器提取到的页码链接所对应的页面中
  4. 注意事项:

    • 链接提取器和规则解析器是一一对应关系
  • 基于CrawlSpider实现深度数据爬取

    • spider文件
    # -*- coding: utf-8 -*-
    import scrapy
    from scrapy.linkextractors import LinkExtractor
    from scrapy.spiders import CrawlSpider, Rule
    from sunspider.items import SunspiderItem, SunspiderItemSecond
    
    
    class SunSpiderSpider(CrawlSpider):
        name = 'sun_spider'
        # allowed_domains = ['www.xxx.com']
        start_urls = ['http://wz.sun0769.com/index.php/question/questionType?type=4&page=']
        # 链接提取器  两层数据爬取,写两个链接提取器,链接提取器和规则解析器是一一对应关系
        link = LinkExtractor(allow=r'type=4&page=\d+')
        link_detail = LinkExtractor(allow=r'question/\d+/\d+\.shtml')
        rules = (
            # 实例化Rule(规则解析器)的对象
            Rule(link, callback='parse_item', follow=True),
            Rule(link_detail, callback='parse_item_content', follow=True),
    
        )
    
        def parse_item(self, response):
            tr_list = response.xpath('//*[@id="morelist"]/div/table[2]//tr/td/table//tr')
            for tr in tr_list:
                title = tr.xpath('./td[2]/a[2]/@title').extract_first()
                status = tr.xpath('./td[3]/span/text()').extract_first()
                num = tr.xpath('./td[1]/text()').extract_first()
                item = SunspiderItem()
                item['title'] = title
                item['status'] = status
                item['num'] = num
                yield item
    
        def parse_detail(self, response):
            content = response.xpath('/html/body/div[9]/table[2]/tbody/tr[1]//text()').extract()
            content = ''.join(content)
            num = response.xpath('/html/body/div[9]/table[1]/tbody/tr/td[2]/span[2]/text()').extract_first()
            if num:
                num = num.split(':')[-1]
                item = SunspiderItemSecond()
                item['content'] = content
                item['num'] = num
                yield item
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    • items.py文件

      import scrapy
      # 定义两个类,并且通过某种方式(num)标识两个类之间的对应关系
      class SunspiderItem(scrapy.Item):
          title = scrapy.Field()
          status = scrapy.Field()
          num = scrapy.Field()
      
      class SunspiderItemSecond(scrapy.Item):
          content = scrapy.Field()
          num = scrapy.Field()
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
    • pipelines.py文件

      • 存储数据
      class SunspiderPipeline(object):
          def process_item(self, item, spider):
              # 判断item是哪一个类封装
              if item.__class__.__name__ == "SunspiderItemSecond":
                  content = item['content']
                  num = item['num']
                  print(content, num)
              else:
                  title = item['title']
                  status = item['status']
                  num = item['num']
      
                  print(title, status, num)
              return item
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14

# 2.分布式爬虫

  • 什么是分布式爬虫

    • 基于多台电脑组件一个分布式机群,然后让每一台电脑执行同一组程序,让后让他们对同一个网站的数据进行分布式爬取
  • 为什么使用分布式爬虫

    • 提示爬取数据效率
  • 如何实现分布式爬虫

    • 基于scrapy + redis 的形式实现分布式
      • 原生的scrapy框架不能实现分布式,原因:
        1. 调度器无法被分布式机群共享
        2. 管道无法数据共享
      • scrapy框架和scrapy-redis 组件实现的分布式
      • scrapy-redis 组件作用:
        1. 提供可以被共享的调度器和管道
  • 环境安装

    • redis
    • pip install scrapy-redis
  • 编码流程

    1. 创建一个工程

    2. 创建一个爬虫文件:基于CrawlScrapy

      • 修改当前的爬虫文件
        • 导包:from scrapy_redis.spiders import RedisCrawlSpider
        • 将当前爬虫类的父类修改成RedisCrawlSpider
        • 将start_urls替换成redis_key = ‘xxx’ #表示的是可被共享调度器中队列的名称
        • 编写爬虫类爬取数据的操作
    3. 对settings进行配置:

      • 指定管道:

        # 开启可以被共享的管道
        ITEM_PIPELINES = {
            'scrapy_redis.pipelines.RedisPipeline': 400
        }
        
        1
        2
        3
        4
      • 指定调度器

        # 增加了一个去重容器类的配置, 作用使用Redis的set集合来存储请求的指纹数据, 从而实现请求去重的持久化
        DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"
        # 使用scrapy-redis组件自己的调度器
        SCHEDULER = "scrapy_redis.scheduler.Scheduler"
        # 配置调度器是否要持久化, 也就是当爬虫结束了, 要不要清空Redis中请求队列和去重指纹的set。如果是True, 就表示要持久化存储, 就不清空数据, 否则清空数据
        SCHEDULER_PERSIST = True
        
        1
        2
        3
        4
        5
        6
      • 指定redis的服务

        REDIS_HOST = 'redis服务的ip地址'
        REDIS_PORT = 6379
        
        1
        2
    4. redis的配置文件进行配置:redis.windows.conf

      • 56行:#bind 127.0.0.1

      • 75行:protected-mode no

      • 携带配置文件启动redis服务

        • ./redis-server redis.windows.conf
      • 启动redis的客户端

        • redis-cli
    5. 执行当前的工程:

       进入到爬虫文件对应的目录中:scrapy runspider xxx.py
      
    6. 向调度器队列中仍入一个起始的url:

      • 队列在哪里呢?答:队列在redis中
        • lpush fbsQueue www.xxx.com

# 3.增量式爬虫

  • 概念:检测网站数据跟新的情况,爬取更新数据

  • 核心:去重!!!

  • 增量式爬虫

    • 深度爬取类型的网站中需要对详情页的url进行记录和检测

      • 记录:将爬取过的详情页的url进行记录保存

        • url存储到redis的set中
        • redis的sadd方法存取时,如果数据存在返回值为0,如果不存在返回值为1;
      • 检测:如果对某一个详情页的url发起请求之前先要取记录表中进行查看,该url是否存在,存在的话以为 着这个url已经被爬取过了。

      • 代码示例

        spider.py文件

      import scrapy
      from scrapy.linkextractors import LinkExtractor
      from scrapy.spiders import CrawlSpider, Rule
      from redis import Redis
      from zjs_moviePro.items import ZjsMovieproItem
      class MovieSpider(CrawlSpider):
          name = 'movie'
          conn = Redis(host='127.0.0.1',port=6379)
          # allowed_domains = ['www.xxx.com']
          start_urls = ['https://www.4567tv.tv/index.php/vod/show/id/6.html']
      
          rules = (#/index.php/vod/show/id/6/page/2.html
              Rule(LinkExtractor(allow=r'id/6/page/\d+\.html'), callback='parse_item', follow=False),
          )
      
          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/div/h4/a/text()').extract_first()
                  detail_url = 'https://www.4567tv.tv'+li.xpath('./div/div/h4/a/@href').extract_first()
                  ex = self.conn.sadd('movie_detail_urls',detail_url)
                  if ex == 1:#向redis的set中成功插入了detail_url
                      print('有最新数据可爬......')
                      item = ZjsMovieproItem()
                      item['name'] = name
                      yield scrapy.Request(url=detail_url,callback=self.parse_detail,meta={'item':item})
                  else:
                      print('该数据已经被爬取过了!')
          def parse_detail(self,response):
              item = response.meta['item']
              desc = response.xpath('/html/body/div[1]/div/div/div/div[2]/p[5]/span[2]/text()').extract_first()
              item['desc'] = desc
      
              yield item
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      • item中创建属性

        import scrapy
        class ZjsMovieproItem(scrapy.Item):
            # define the fields for your item here like:
            name = scrapy.Field()
            desc = scrapy.Field()
        
        1
        2
        3
        4
        5
      • 管道文件中

        class ZjsMovieproPipeline(object):
            def process_item(self, item, spider):
                conn = spider.conn
                conn.lpush('movie_data',item)
                return item
        
        1
        2
        3
        4
        5
    • 非深度爬取类型的网站:

      • 名词:数据指纹
        • 一组数据的唯一标识
#Python#
上次更新: 2023/04/16, 18:35:33
scrapy框架-媒体文件爬取-middleware

← scrapy框架-媒体文件爬取-middleware

最近更新
01
go与http代理
05-24
02
自制申威架构k8s-reloader
12-06
03
Docker Buildx 教程
12-01
更多文章>
Theme by Vdoing | Copyright © 2020-2024 小刘扎扎 | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式