爬虫入门_9:增量式爬虫

  • 概念:检测网站数据更新的情况,只会爬取网站最新更新出来的数据
  • 增量式爬取的核心是去重,去重方法如下:
    • 思路:通过redis的set集合实现去重的目的

    • 将爬取过程中产生的URL存储到redis的set数据结构中

      • 根据sadd(key,value) 的返回结果,判断此 URL 是否已爬取过

      • 1 表示没有爬取过,则发起请求; 0 表示已爬取过,则不进行请求

      • 示例:在redis中输入以下内容,可以得到下图

        # 向name(set集)中添加一个'jay'
        sadd name jay
        sadd name lily
        sadd name jay  # 再次添加后,会返回0,表示没有添加,因为name中已经有了
        

      爬虫入门_9:增量式爬虫

案例

  • 需求:增量式爬取电影网站中最近更新的数据

  • 分析:

    • 指定一个起始的url

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

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

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

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

      将爬取过的电影详情页的url存储到Redis的set数据结构,实现去重

    • 对详情页的url发起请求,然后解析出电影的名称和简介

    • 进行持久化存储

  • 代码实现

    • 启动redis服务和打开redis终端

      • 启动redis:双击红框,启动服务

    爬虫入门_9:增量式爬虫

    • 打开redis客户端:注意要修改编码格式为’UTF-8‘,不然中文显示出来都是16进制的,具体操作如下:

      • 临时修改:只作用于当前窗口,先进入cmd命令窗口(快捷键win键+R)

      • 直接输入“chcp 65001”,回车键(Enter键)执行,这时候该窗口编码已经是UTF-8编码了。

      • 然后进入redis安装的目录下

      爬虫入门_9:增量式爬虫

      • 输入redis-cli --raw,进入redis客户端

      爬虫入门_9:增量式爬虫

      • 输入flushall : 清空redis的数据
    • 创建一个工程:scrapy startproject moviePro

    • 进入到工程目录中:cd moviePro

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

      scrapy genspider -t crawl movie www.xxx.com

    • 编写爬虫文件movie.py

      import scrapy
      from scrapy.linkextractors import LinkExtractor
      from scrapy.spiders import CrawlSpider, Rule
      from moviePro.items import MovieproItem
      from redis import Redis
      
      
      class MovieSpider(CrawlSpider):
          name = 'movie'
          # allowed_domains = ['www.xxx.com']
          start_urls = ['https://www.4567kp.com/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//div[1]/div/div/div/div[2]/ul/li')
              print(len(li_list))
              for li in li_list:
                  # 获取详情页的url
                  detail_url = 'https://www.4567kp.com' + li.xpath('./div/a/@href').extract_first()
      
                  # 将详情页的url存入redis的set中
                  ex = self.conn.sadd('urls', detail_url)
                  # ex == 1 :字符串插入成功
                  # ex == 0 :插入的字符串重复了,利用redis的set集合去重
                  if ex == 1:
                      print("该url没有被爬取过,可以进行数据爬取")
                      yield scrapy.Request(url=detail_url, callback=self.parse_detail)
                  else:
                      print("数据还没有更新,暂无新数据可爬取!")
      
          # 解析详情页中的电影名称和简介,进行持久化存储
          def parse_detail(self, response):
              item = MovieproItem()
              item['name'] = response.xpath('/html//div[1]/div/div/div/div[2]/h1/text()').extract_first()
              item['desc'] = response.xpath('/html//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()
      
    • 在pipelines.py中编写代码

      class MovieproPipeline:
          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
      
    • 修改配置文件settings.py

      USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36'
      
      # Obey robots.txt rules
      # True:遵从robots协议
      ROBOTSTXT_OBEY = False
      
      # 显示指定的类型的日志信息
      LOG_LEVEL = 'ERROR'
      
      ITEM_PIPELINES = {
         'moviePro.pipelines.MovieproPipeline': 300,
      }
      
    • 在终端中输入:scrapy crawl movie,即可

      • 第一次爬取数据的时候,结果如下

      爬虫入门_9:增量式爬虫

      • 第二次爬取该网站数据时,结果如下

      爬虫入门_9:增量式爬虫

    • 在redis中查看存储情况

      • keys * : 查看数据存储结果列表

      • smembers urls : 查看urls存储内容

      爬虫入门_9:增量式爬虫

      • llen movieData:查看数据大小

      • lrange movieData 0 4:查看前5条样例数据

        爬虫入门_9:增量式爬虫

  • 报错

    1. 在运行脚本时,出现了如下的一个bug

      redis.exceptions.DataError: Invalid input of type: 'dict'. Convert to a bytes, string, int or float first.
      
      • 问题点:是 因为python中的redis版本过高导致的,需降低版本
      • 解决方法:
        • 查看python中安装的redis的版本,发现是4.0以上的版本
        • 将版本降低到2.10.6:pip install -U redis==2.10.6
        • 再次运行脚本,发现运行成功

参考链接

windows系统修改cmd窗口utf-8编码格式

Python爬虫学习视频

如果本文对你有帮助,记得“点赞、收藏”哦~

上一篇:01-短信验证码、动态验证码


下一篇:远程连接redis