7-爬虫-crawlSpider、分布式爬虫、增量式爬虫、爬虫内容总结

crawlSpider

是Spider的一个子类。自己派生出独有的方法和属性。
功能:作用全站数据爬取场景
使用:
  - 创建工程
  - cd 工程
  - 创建爬虫文件:
    - 创建一个基于CrawlSpider的爬虫文件
    - 指令:scrapy genspider -t crawl spiderName www.xxx.com
  - 执行工程

import scrapy
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule


class CrawlModelSpider(CrawlSpider):
    name = 'crawl_model'
    # allowed_domains = ['www.xxx.com']
    start_urls = ['https://www.4567kan.com/index.php/vod/show/class/动作/id/1.html']

    # LinkExtractor叫做链接提取器
    # 作用:根据指定的规则(allow='正则')在页面中进行相关链接(url)的提取
    link = LinkExtractor(allow=r'/id/1/page/\d+\.html')
    rules = (
        # Rule叫做规则解析器,链接提取器是被作用在规则解析器
        # 作用:可以接受link提取到的链接,且对链接进行请求发送,根据指定规则(callback)对请求到的数据进行数据解析
        # follow=True:可以将 链接提取器 继续作用到 链接提取器 提取到的页码 所对应的页面源码中
        Rule(link, callback='parse_item', follow=True),
    )

    def parse_item(self, response):
        print(response)

crawlspider全站数据爬取

import scrapy
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule
import scrapy
from moviePro.items import MovieproItem


class MovieSpider(CrawlSpider):
    name = 'movie'
    # allowed_domains = ['www.xxx.com']
    start_urls = ['https://www.4567kan.com/index.php/vod/show/class/动作/id/1/page/1.html']

    rules = (
        # 提取页码链接
        Rule(LinkExtractor(allow=r'/id/1/page/\d+\.html'), callback='parse_item', follow=False),
        # 提取详情页链接
        # Rule(LinkExtractor(allow=r'/movie/index\d+\.html'),callback='parse_detail',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:
            title = li.xpath('./div/a/@title').extract_first()
            detail_url = 'https://www.4567kan.com' + li.xpath('./div/a/@href').extract_first()
            item = MovieproItem()
            item['title'] = title
            yield scrapy.Request(url=detail_url, callback=self.parse_detail, meta={'item': item})
   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.meta['item']
        item['desc'] = desc
        yield item

分布式爬虫

概念:搭建一个分布式机群,然后让每一台电脑进行联合且分布的数据爬取
原生的scrapy框架是无法实现分布式
  - 调度器无法被机群共享
  - 管道无法被共享
必须要要scrapy结合scrapy-redis组件一起实现分布式
  - scrapy-redis组件的作用:
    - 可以给scrapy提供可以被共享的管道和调度器
    - 为什么组件的名称叫做scrapy-redis
      - 爬取到的数据只能存储到redis中
环境安装
  - pip install scrapy-redis
实现流程
  - 1.新建工程(基于CrawlSpider),也可以用Spider
  - 2.修改爬虫文件
    - 导包:from scrapy_redis.spiders import RedisCrawlSpider
    - 修改当前爬虫类的父类为RedisCrawlSpider
    - 将start_urls替换成redis_key属性,属性值为字符串,表示可以被共享的调度器队列的名称
    - 编写后序的爬虫文件相关操作
  - 3.进行setting配置文件的配置(直接将配置代码复制进配置文件中)
    - 指定管道

      # 指定使用scrapy-redis组件中的调度器
      # 使用scrapy-redis组件的去重队列
      DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"
      # 使用scrapy-redis组件自己的调度器
      SCHEDULER = "scrapy_redis.scheduler.Scheduler"
      # 帮分布式实现增量式
      SCHEDULER_PERSIST = True

    - 指定调度器

      # 指定共享管道(不能修改,只能往redis存)
      ITEM_PIPELINES = {
        'scrapy_redis.pipelines.RedisPipeline': 400
      }

    - 指定redis

      # 指定redis数据库服务器和端口号
      REDIS_HOST = '127.0.0.1'
      REDIS_PORT = 6379

  - 4.对redis的配置文件进行配置:redis.windows.conf
    - 56行:关闭默认绑定,允许外网有访问该redis数据库, # bind 127.0.0.1   # 将这个代码注释掉
    - 75行:关闭保护模式,允许其他设备有redis写入的权限,protected-mode no   #  将参数由yes改为no
  - 5.启动redis的服务端和客户端
  - 6.执行工程
  - 7.向调度器队列中扔入一个起始的url:调度器的队列是存在于redis中
    - 在redis的客户端执行如下指令:
      - lpush 调度器队列的名称 起始的url
      - 该指令一旦执行成功,则分布式机群就可以进行数据的爬取
  - 8.可以在redis中查看爬取到的数据
    - xxx:items:存储的是爬取到的数据

 settings.py

# 指定使用scrapy-redis组件中的调度器
# 使用scrapy-redis组件的去重队列
DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"
# 使用scrapy-redis组件自己的调度器
SCHEDULER = "scrapy_redis.scheduler.Scheduler"
# 帮分布式实现增量式
SCHEDULER_PERSIST = True

# 指定共享管道(不能修改,只能往redis存)
ITEM_PIPELINES = {
    'scrapy_redis.pipelines.RedisPipeline': 400
}

# 指定redis数据库服务器和端口号
REDIS_HOST = '127.0.0.1'
REDIS_PORT = 6379

fbs.py

import scrapy
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule
from scrapy_redis.spiders import RedisCrawlSpider
from fbsPro.items import FbsproItem


class FbsSpider(RedisCrawlSpider):
    name = 'fbs'
    # allowed_domains = ['www.xxx.com']
    # start_urls = ['http://www.xxx.com/']
    redis_key = 'sun_queue'  # 调度器队列的名称
    rules = (
        Rule(LinkExtractor(allow=r'id=1&page=\d+'), callback='parse_item', follow=True),
    )

    def parse_item(self, response):
        # 在xpath表达式中不可以出现tbody标签,否则xpath表达式无效
        li_list = response.xpath('/html/body/div[2]/div[3]/ul[2]/li')
        for li in li_list:
            status = li.xpath('./span[2]/text()').extract_first()
            title = li.xpath('./span[3]/a/text()').extract_first()
            item = FbsproItem()
            item['title'] = title
            item['status'] = status

            yield item

items.py

import scrapy


class FbsproItem(scrapy.Item):
    # define the fields for your item here like:
    title = scrapy.Field()
    status = scrapy.Field()

增量式爬虫

概念:来检测网站数据更新情况。为爬取网站最新更新出来的数据。
实现核心:记录表
  - 记录表中要存储爬取过的记录。
  - 在电影网站中,每一部电影详情页的url就可以作为电影的唯一标识(爬取的记录)
  - 谁可以充当记录表:
    - 1.记录表需要有去重的功能
    - 2.记录表需要持久化存储
    - 可以使用redis中的set集合充当记录表

 zls.py

import scrapy
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule
from zlsPro.items import ZlsproItem
from redis import Redis


class ZlsSpider(CrawlSpider):
    name = 'zls'
    conn = Redis(host='127.0.0.1', port=6379)
    # allowed_domains = ['www.xxx.com']
    start_urls = ['https://www.4567kan.com/index.php/vod/show/class/%E5%8A%A8%E4%BD%9C/id/1/page/1.html']

    rules = (
        Rule(LinkExtractor(allow=r'/id/1/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:
            title = li.xpath('./div/a/@title').extract_first()
            detail_url = 'https://www.4567kan.com' + li.xpath('./div/a/@href').extract_first()
            # ex=1:插入成功,0表示插入失败(插入了重复的数据)
            ex = self.conn.sadd('movie_urls', detail_url)
            if ex == 1:
                item = ZlsproItem()
                item['title'] = title
                print('正在爬取的电影是:', title)
                yield scrapy.Request(url=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.meta['item']
        item['desc'] = desc
        yield item

pipelines.py

class ZlsproPipeline:
    def process_item(self, item, spider):
        spider.conn.lpush('movie_data', item)
        return item

items.py

import scrapy


class ZlsproItem(scrapy.Item):
    # define the fields for your item here like:
    title = scrapy.Field()
    desc = scrapy.Field()

爬虫内容总结

反爬机制
  - robots协议
  - UA检测
  - 动态加载数据
  - 验证码
  - cookie
  - 代理
  - js加密
    - js逆向
  - js混淆
  - 动态变化的请求参数

爬虫
  - requests
    - get,post请求:方法参数
    - 参数动态
    - cookie,验证码,代理,模拟登录
  - 数据解析
    - xpath,bs4
  - 异步爬虫
    - 线程池,协程,生产者消费者模式
  - selenium
    - 爬取动态加载数据
    - 模拟登录
  - scrapy
    - 请求发送
    - 数据解析
    - 全站数据爬取
    - 手动请求发送
    - 请求传参实现的深度爬取
    - 核心组件
    - 中间件
    - crawlspider
    - 分布式
    - 增量式

posted @ 2020-07-10 16:24  电竞杰森斯坦森  阅读(330)  评论(0编辑  收藏  举报