Python爬虫学习笔记-第二十五课(Scrapy-Redis的学习与使用)

1. Scrapy-Redis入门

1.1 基本概念

为什么要学习Scrapy-Redis?
第一个:了解工作流程(面试);
第二个:要求会把普通的爬虫改写成分布式爬虫。

集群:多个人在做同一件事;
分布式:多个人在做不同的事,协同完成任务,拥有更高的效率。

scrapy和scrapy-redis有什么区别?

  • scrapy是爬虫的一个框架,爬取效率非常高,具有高度的可定制性,不支持分布式;
  • scrapy-redis是基于redis数据库,运行在scrapy框架之上的一个组件,可以让scrapy支持分布式策略,支持主从同步。

scrapy-redis的工作流程:
在这里插入图片描述
scrapy-redis主要解决以下两个问题:

  • 如何保证爬取数据不重复;
  • 怎么把不同机器上的数据保存到统一的地方。

scrapy-redis在工作流程上与普通scrapy的不同:

  • 引擎拿到爬取的url后给调度器,但是url的入列和去重校验交由redis执行;
  • 爬虫文件处理完response后,原本交给管道的数据现存储到redis中。

综上,redis中存储爬取的数据、待爬取的request对象和爬取过的request对象,后两项保证爬取数据的不重复性。

1.2 安装Scrapy-Redis

在python中安装scrapy-redis:
pip install scrapy_redis -i https://pypi.douban.com/simple/
在这里插入图片描述
关于scrapy-redis的安装细节,比如python版本、redis版本等都有说明,这里不再赘述。

1.3 example-redis解析

github上有基于scrapy-redis框架的示例项目。

1 clone github scrapy_redis源码⽂件
2 git clone https://github.com/rolando/scrapy-redis.git

example-redis的文件目录结构:
在这里插入图片描述
example-redis中的爬虫文件与普通爬虫文件的不同点:
在这里插入图片描述
关于settings文件的变化:
在这里插入图片描述
运行example-redis项目,具体方法和普通scrapy项目一致。
在这里插入图片描述
在终端中验证保存的数据:

127.0.0.1:6379> keys *
1) "dmoz:requests" # 存放的是待爬取的requests对象,zset类型
2) "dmoz:items" # 爬取到的信息
3) "dmoz:dupefilter" # 爬取过的requests对象
127.0.0.1:6379> type dmoz:requests
zset
127.0.0.1:6379> type dmoz:dupefilter
set

1.4 分布式爬虫

观察myspider-redis.py文件:
在这里插入图片描述
如何把普通的爬虫文件改写成分布式爬虫文件?
普通的爬虫:

  • scrapy项目/爬虫项目;
  • 明确爬取的目标;
  • 保存数据。

改写成分布式:

  1. 改写爬虫文件:
    1.1 导入模块;
    1.2 继承类;
    1.3 把start_urls --> redis_key。
  2. 改写配置文件。

domz爬虫的数据是怎么存储到数据库?
在这里插入图片描述
连接数据库在StrictRedis类的init函数中实现(源码中的defaults.py)。我们只需在settings文件中打开管道,在爬虫文件中yield对应的数据即可保存到本地数据库。

2. 案例演示

案例链接:http://book.dangdang.com/
爬取当当网图书分类,假定“特色书单”为大分类,里面的“童书”、“文艺”等为中分类,童书里面的“儿童国际大奖书单来了!”、“中关村三小推荐阅读书单”等为小分类。
在这里插入图片描述
需求:获取大中小三级分类以及图片的名字以及图片的地址。

2.1 页面分析

大分类在 div class="con flq_body"下面class="level_one"/dl/dt/span文本:
在这里插入图片描述
在这里插入图片描述
注意:span标签在网页源码中没有,有的大标题是多个,通过//找到所有的需要用extract()

中分类的内容都在div class="inner_dl"/dt,小分类的内容都在div class="inner_dl"/dd/a
在这里插入图片描述
在这里插入图片描述
注意:中分类在网页源码中的标签与element中一致。

小分类详情页面的结构:
在这里插入图片描述
想要爬取的是图书的名字以及对应的图片,所有的数据都是在ul标签下面的li中。
在这里插入图片描述
注意,在网页的源码当中src = 'images/model/guan/url_none.png'与我们希望的图片url不符,这里只能找data-original.
注意:每次爬取数据之前,要检查网页源码和elements选项当中的数据是否一致。

2.2 编写代码

​改写程序

  1. 改写爬虫文件
    1.1 导入模块
    1.2 继承类
    1.3 把start_urs --> redis_key
  2. 改写配置文件

创建相应的scrapy项目,爬虫文件如下:

import scrapy
from copy import deepcopy
from scrapy_redis.spiders import RedisSpider

class DdSpider(RedisSpider):
    name = 'dd'
    allowed_domains = ['dangdang.com']
    # start_urls = ['http://book.dangdang.com/']
    redis_key = 'dd'

    def parse(self, response):
        # 获取所有div标签
        div_list = response.xpath('//div[@class="con flq_body"]/div')
        for div in div_list:
            item = {}
            # 获取大分类名字
            item['b_cate'] = div.xpath('./dl/dt//text()').extract()
            if item['b_cate']:
                item['b_cate'] = [i.strip() for i in item['b_cate'] if len(i.strip()) > 0]
                item['b_cate'] = ''.join(item['b_cate'])
                # print(item)

            dl_list = div.xpath('.//dl[@class="inner_dl"]')
            for dl in dl_list:
                # 获取中分类名字
                item['m_cate'] = dl.xpath('./dt//text()').extract()
                if item['m_cate']:
                    item['m_cate'] = [i.strip() for i in item['m_cate'] if len(i.strip()) > 0]
                    item['m_cate'] = item['m_cate'][0]
                    # print(item['m_cate'])
                # 获取下分类
                a_list = dl.xpath('./dd/a')
                for a in a_list:
                    item['s_cate'] = a.xpath('./text()').extract_first()
                    # 获取列表页面url
                    item['s_href'] = a.xpath('./@href').extract_first()
                    if item['s_href']:
                        yield scrapy.Request(
                            url=item['s_href'],
                            callback=self.parse_book_list,
                            meta={'item': deepcopy(item)}
                        )
                    # print(item)

    def parse_book_list(self, response):
        item = response.meta.get('item')
        # 获取小分类详情页中的li标签
        li_list = response.xpath('//ul[@class="list_aa "]/li')
        for li in li_list:
            # 获取图片的url
            item['book_img'] = li.xpath('./a[@class="img"]/img/@data-original').extract_first()
            # 获取图片的名字
            item['book_name'] = li.xpath('./p[@class="name"]/a/@title').extract_first()
            print(item)
            yield item

settings文件:

BOT_NAME = 'dangdang'

SPIDER_MODULES = ['dangdang.spiders']
NEWSPIDER_MODULE = 'dangdang.spiders'
# LOG_LEVEL = 'WARNING'

# 去重过滤
DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"
# 指定Scheduler队列
SCHEDULER = "scrapy_redis.scheduler.Scheduler"
SCHEDULER_PERSIST = True

# Obey robots.txt rules
ROBOTSTXT_OBEY = False
DOWNLOAD_DELAY = 1

# Override the default request headers:
DEFAULT_REQUEST_HEADERS = {
    'User_Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.104 Safari/537.36',
    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
    'Accept-Language': 'en',
}

ITEM_PIPELINES = {
   'book.pipelines.BookPipeline': 300,
   'scrapy_redis.pipelines.RedisPipeline': 400,
}

此时爬虫程序进入一个在阻塞状态,我们需要在redis中将start_url添加到相应的key;
在爬虫文件里面千万不要忘记yield数据。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值