scrapy_分布式_reids

进阶式练习

  • CrawlSpider:类,Spider的一个子类

    • 全站数据爬取的方式
      • 基于Spider:手动请求
      • 基于CrawlSpider
    • CrawlSpider的使用:
      • 创建一个工程
      • cd XXX
      • 创建爬虫文件(CrawlSpider):
        • scrapy genspider -t crawl xxx www.xxxx.com
        • 链接提取器:
          • 作用:根据指定的规则(allow)进行指定链接的提取
        • 规则解析器:
          • 作用:将链接提取器提取到的链接进行指定规则(callback)的解析
            #需求:爬取sun网站中的编号,新闻标题,新闻内容,标号
        • 分析:爬取的数据没有在同一张页面中。
        • 1.可以使用链接提取器提取所有的页码链接
        • 2.让链接提取器提取所有的新闻详情页的链接
  • 分布式爬虫

    • 概念:我们需要搭建一个分布式的机群,让其对一组资源进行分布联合爬取。

    • 作用:提升爬取数据的效率

    • 如何实现分布式?

      • 安装一个scrapy-redis的组件
      • 原生的scarapy是不可以实现分布式爬虫,必须要让scrapy结合着scrapy-redis组件一起实现分布式爬虫。
      • 为什么原生的scrapy不可以实现分布式?
        • 调度器不可以被分布式机群共享
        • 管道不可以被分布式机群共享
      • scrapy-redis组件作用:
        • 可以给原生的scrapy框架提供可以被共享的管道和调度器
      • 实现流程
        • 创建一个工程

        • 创建一个基于CrawlSpider的爬虫文件

        • 修改当前的爬虫文件:

          • 导包:from scrapy_redis.spiders import RedisCrawlSpider
          • 将start_urls和allowed_domains进行注释
          • 添加一个新属性:redis_key = ‘sun’ 可以被共享的调度器队列的名称
          • 编写数据解析相关的操作
          • 将当前爬虫类的父类修改成RedisCrawlSpider
        • 修改配置文件settings

          • 指定使用可以被共享的管道:
            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相关操作配置:

          • 配置redis的配置文件:
            • linux或者mac:redis.conf
            • windows:redis.windows.conf
            • 代开配置文件修改:
              • 将bind 127.0.0.1进行删除
              • 关闭保护模式:protected-mode yes改为no
          • 结合着配置文件开启redis服务
            • redis-server 配置文件
          • 启动客户端:
            • redis-cli
        • 执行工程:

          • scrapy runspider xxx.py
        • 向调度器的队列中放入一个起始的url:

          • 调度器的队列在redis的客户端中
            • lpush xxx www.xxx.com
        • 爬取到的数据存储在了redis的proName:items这个数据结构中

  • 增量式爬虫

    • 概念:监测网站数据更新的情况,只会爬取网站最新更新出来的数据。
    • 分析:
      • 指定一个起始url

      • 基于CrawlSpider获取其他页码链接

      • 基于Rule将其他页码链接进行请求

      • 从每一个页码对应的页面源码中解析出每一个电影详情页的URL

      • 核心:检测电影详情页的url之前有没有请求过

        • 将爬取过的电影详情页的url存储
          • 存储到redis的set数据结构
      • 对详情页的url发起请求,然后解析出电影的名称和简介

      • 进行持久化存储

settings.py
设置这里一如既往常规

USER_AGENT = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36'

# Obey robots.txt rules
ROBOTSTXT_OBEY = False
LOG_LEVEL = 'ERROR'
ITEM_PIPELINES = {
   'moviePro.pipelines.MovieproPipeline': 300,
}

movie.py

# -*- coding: utf-8 -*-
import scrapy
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule

from redis import Redis
from moviePro.items import MovieproItem
class MovieSpider(CrawlSpider):
    name = 'movie'
    # allowed_domains = ['www.ccc.com']
    start_urls = ['https://www.4567tv.tv/frim/index1.html']

    rules = (
        Rule(LinkExtractor(allow=r'/frim/index1-\d+\.html'), callback='parse_item', follow=True),
    )
    # 创建redis链接对象
    conn = Redis(host='127.0.0.1', port=6379)

    #用于解析每一个页码对应页面中的电影详情页的url
    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:
            # 获取详情页的url
            detail_url = 'https://www.4567tv.tv' + li.xpath('./div/a/@href').extract_first()

            # 将详情页的url存入redis的set中
            ex = self.conn.sadd('urls', detail_url)
            if ex == 1:
                print('该url没有被爬取过,可以进行数据的爬取')
                yield scrapy.Request(url=detail_url, callback=self.parst_detail)
            else:
                print('数据还没有更新,暂无新数据可爬取!')

    # 解析详情页中的电影名称和类型,进行持久化存储
    def parst_detail(self, response):
        item = MovieproItem()
        item['name'] = response.xpath('/html/body/div[1]/div/div/div/div[2]/h1/text()').extract_first()
        item['desc'] = response.xpath('/html/body/div[1]/div/div/div/div[2]/p[5]/span[2]//text()').extract()
        item['desc'] = ''.join(item['desc'])
        yield item

items.py

import scrapy


class MovieproItem(scrapy.Item):
    # define the fields for your item here like:
    name = scrapy.Field()
    desc = scrapy.Field()
    # pass

piplines.py

from redis import Redis
class MovieproPipeline(object):
    conn = None
    def open_spider(self,spider):
        self.conn = spider.conn
    def process_item(self, item, spider):
        dic = {
            'name':item['name'],
            'desc':item['desc']
        }
        # print(dic)
        self.conn.lpush('movieData',dic)
        return item
上一篇:liunx Redis的安装和后台启动


下一篇:Python 分布式缓存之Reids数据类型操作详解