详解Scrapy Redis入门实战

简介

scrapy-redis是一个基于redis的scrapy组件,用于快速实现scrapy项目的分布式部署和数据爬取,其运行原理如下图所示。

Scrapy-Redis特性

分布式爬取

你可以启动多个共享同一redis队列的爬虫实例,多个爬虫实例将各自提取到或者已请求的Requests在队列中统一进行登记,使得Scheduler在请求调度时能够对重复Requests进行过滤,即保证已经由某一个爬虫实例请求过的Request将不会再被其他的爬虫实例重复请求。

分布式数据处理

将scrapy爬取到的items汇聚到同一个redis队列中,意味着你可以根据你的需要启动尽可能多的共享这个items队列的后处理程序。

Scrapy即插即用组件

Scheduler调度器 + Duplication重复过滤器、Item Pipeline、基础Spider爬虫

Scrapy-Redis示例

本文将以爬取京东所有图书分类下的图书信息为例对Scrapy-Redis的用法进行示例。

开发环境

  • Python 3.7
  • Redis 3.2.100

下面列举出了 Python 中 Scrapy-Redis 所需要的各个模块及其版本:

  • redis 2.10.6
  • redis-py-cluster 1.3.6
  • scrapy-redis 0.6.8
  • scrapy-redis-cluster 0.4

在开发之前需要先安装好以上模块,以scrapy-redis-cluster模块为例,使用pip进行安装的命令如下:

pip install scrapy-redis-cluster # 安装模块
pip install scrapy-redis-cluster==0.4 # 安装模块时指定版本
pip install --upgrade scrapy-redis-cluster # 升级模块版本

创建项目

在Windows命令行执行如下命令完成项目创建:

d:\scrapy>scrapy startproject jd_book

执行完该命令后,将会在当前目录下创建包含下列内容的 jd_book 目录:

定义Item

在items.py中把我们将要爬取的图书字段预先定义好。

# -*- coding: utf-8 -*-

import scrapy

class JdBookItem(scrapy.Item):
  b_cate = scrapy.Field() # 图书所属一级分类名称
  s_cate = scrapy.Field() # 图书所属二级分类名称
  s_href = scrapy.Field() # 图书所属二级分类地址
  book_name = scrapy.Field() # 名称
  book_img = scrapy.Field() # 封面图片地址
  book_author = scrapy.Field() # 作者
  book_press = scrapy.Field() # 出版社
  book_publish_date = scrapy.Field() # 出版日期
  book_sku = scrapy.Field() # 商品编号
  book_price = scrapy.Field() # 价格

创建Spider

在Windows命令行执行如下命令完成Spider创建:

d:\scrapy\jd_book>cd jd_book
d:\scrapy\jd_book>scrapy genspider jdbook jd.com

执行完该命令后,将会在 jd_book 的 spiders 目录下生成一个 jdbook.py 文件 :

jdbook.py的完整爬虫代码如下。

# -*- coding: utf-8 -*-
import scrapy
import json
import urllib
from copy import deepcopy
from jd_book.items import JdBookItem

class JdbookSpider(scrapy.Spider):
  name = 'jdbook'
  allowed_domains = ['jd.com','3.cn']
  start_urls = ['https://book.jd.com/booksort.html']

  def parse(self, response): # 处理图书分类页
    dt_list = response.xpath("//div[@class='mc']/dl/dt") # 提取一级分类元素
    for dt in dt_list:
      item = JdBookItem()
      item["b_cate"] = dt.xpath("./a/text()").extract_first() # 提取一级分类名称
      em_list = dt.xpath("./following-sibling::dd[1]/em") # 提取二级分类元素
      for em in em_list:
        item["s_cate"] = em.xpath("./a/text()").extract_first() # 提取二级分类名称
        item["s_href"] = em.xpath("./a/@href").extract_first() # 提取二级分类地址
        if item["s_href"] is not None:
          item['s_href'] = "https:" + item['s_href'] # 补全二级分类地址
          yield scrapy.Request(item['s_href'], callback=self.parse_book_list, meta={"item": deepcopy(item)})

  def parse_book_list(self, response): # 处理二级分类下图书列表页
    item = response.meta['item']
    li_list = response.xpath("//div[@id='plist']/ul/li") # 提取所有的图书元素
    for li in li_list:
      item["book_img"] = li.xpath(".//div[@class='p-img']//img/@data-lazy-img").extract_first()
      if item["book_img"] is None:
        item["book_img"] = li.xpath(".//div[@class='p-img']//img/@src").extract_first()
      if item["book_img"] is not None:
        item["book_img"] = "https:"+item["book_img"]
      item["book_name"] = li.xpath(".//div[@class='p-name']/a/em/text()").extract_first().strip()
      item["book_author"] = li.xpath(".//span[@class='author_type_1']/a/text()").extract()
      item["book_press"] = li.xpath(".//span[@class='p-bi-store']/a/@title").extract_first()
      item["book_publish_date"] = li.xpath(".//span[@class='p-bi-date']/text()").extract_first().strip()
      item["book_sku"] = li.xpath("./div/@data-sku").extract_first()
      price_url = "https://p.3.cn/prices/mgets?skuIds=j_{}".format(item["book_sku"]) # 提取图书价格请求地址
      yield scrapy.Request(price_url, callback=self.parse_book_price, meta={"item": deepcopy(item)})

    # 提取列表页下一页地址
    next_url = response.xpath("//a[@class='pn-next']/@href").extract_first()
    if next_url is not None:
      next_url = urllib.parse.urljoin(response.url, next_url)
      # yield scrapy.Request(next_url,callback=self.parse_book_list,meta={"item":item})

  def parse_book_price(self, response):
    item = response.meta['item']
    item["book_price"] = json.loads(response.body.decode())[0]["op"]
    yield item

修改配置

在settings.py 中增加Scrapy-Redis相关配置。

# -*- coding: utf-8 -*-

BOT_NAME = 'jd_book'

SPIDER_MODULES = ['jd_book.spiders']
NEWSPIDER_MODULE = 'jd_book.spiders'

# Crawl responsibly by identifying yourself (and your website) on the user-agent
USER_AGENT = 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36'

# Obey robots.txt rules
ROBOTSTXT_OBEY = False

######################################################
##############下面是Scrapy-Redis相关配置################
######################################################

# 指定Redis的主机名和端口
REDIS_HOST = 'localhost'
REDIS_PORT = 6379

# 调度器启用Redis存储Requests队列
SCHEDULER = "scrapy_redis.scheduler.Scheduler"

# 确保所有的爬虫实例使用Redis进行重复过滤
DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"

# 将Requests队列持久化到Redis,可支持暂停或重启爬虫
SCHEDULER_PERSIST = True

# Requests的调度策略,默认优先级队列
SCHEDULER_QUEUE_CLASS = 'scrapy_redis.queue.PriorityQueue'

# 将爬取到的items保存到Redis 以便进行后续处理
ITEM_PIPELINES = {
  'scrapy_redis.pipelines.RedisPipeline': 300
}

启动爬虫

至此京东图书项目就算配置完成了,你可以将项目部署到多台服务器中去,并使用如下命令来启动爬虫:

d:\scrapy\jd_book>scrapy crawl jdbook

爬取到的图书数据结构如下:

相应地,在Redis数据库中同时生成了如下3个键:

其中,jdbook:requests 中保存了待爬取的Request对象;jdbook:dupefilter 中保存了已经爬取过的Request对象的指纹;jdbook:items中保存了爬取到的Item对象。

通过上述京东图书项目不难看出,scrapy-redis项目与普通的scrapy项目相比,除了在settings.py配置时额外增加了一些scrapy-redis的专属配置外,其他环节完全相同。

参考文章

https://scrapy-redis.readthedocs.io/en/stable/index.html

到此这篇关于详解Scrapy Redis入门实战的文章就介绍到这了,更多相关Scrapy Redis入门内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 基于scrapy的redis安装和配置方法

    在定向爬虫的制作过程中,使用分布式爬取技术可以显著提高爬取效率.而 Redis 配合 Scrapy 是实现分布式爬取的基础. Redis 是一个高性能的 Key-Value 数据库,它把数据保存在内存里.因此可以有非常快的数据读写速度. scrapy-redis 的安装 pip install scrapy-redis easy_install scrapy-redis 下载 http://redis.io/download 版本推荐 stable 3.0.2 运行redis redis-ser

  • Scrapy基于scrapy_redis实现分布式爬虫部署的示例

    准备工作 1.安装scrapy_redis包,打开cmd工具,执行命令pip install scrapy_redis 2.准备好一个没有BUG,没有报错的爬虫项目 3.准备好redis主服务器还有跟程序相关的mysql数据库 前提mysql数据库要打开允许远程连接,因为mysql安装后root用户默认只允许本地连接,详情请看此文章 部署过程 1.修改爬虫项目的settings文件 在下载的scrapy_redis包中,有一个scheduler.py文件,里面有一个Scheduler类,是用来调

  • scrapy-redis源码分析之发送POST请求详解

    1 引言 这段时间在研究美团爬虫,用的是scrapy-redis分布式爬虫框架,奈何scrapy-redis与scrapy框架不同,默认只发送GET请求,换句话说,不能直接发送POST请求,而美团的数据请求方式是POST,网上找了一圈,发现关于scrapy-redis发送POST的资料寥寥无几,只能自己刚源码了. 2 美团POST需求说明 先来说一说需求,也就是说美团POST请求形式.我们以获取某个地理坐标下,所有店铺类别列表请求为例.获取所有店铺类别列表时,我们需要构造一个包含位置坐标经纬度等

  • scrapy-redis的安装部署步骤讲解

    先说下自己的环境,redis是部署在centos上的,爬虫运行在windows上, 1. 安装redis yum install -y redis 2. 修改配置文件 vi /etc/redis.conf 将 protected-mode no解注释,否则的话,在不设置密码情况下远程无法连接redis 3. 重启redis systemctl restart redis 4. 关闭防火墙 systemctl stop firewalld.service 5. 开始创建scrapy-redis的相

  • Scrapy-Redis结合POST请求获取数据的方法示例

    前言 通常我们在一个站站点进行采集的时候,如果是小站的话 我们使用scrapy本身就可以满足. 但是如果在面对一些比较大型的站点的时候,单个scrapy就显得力不从心了. 要是我们能够多个Scrapy一起采集该多好啊 人多力量大. 很遗憾Scrapy官方并不支持多个同时采集一个站点,虽然官方给出一个方法: **将一个站点的分割成几部分 交给不同的scrapy去采集** 似乎是个解决办法,但是很麻烦诶!毕竟分割很麻烦的哇 下面就改轮到我们的额主角Scrapy-Redis登场了! 能看到这篇文章的小

  • Scrapy-redis爬虫分布式爬取的分析和实现

    Scrapy Scrapy是一个比较好用的Python爬虫框架,你只需要编写几个组件就可以实现网页数据的爬取.但是当我们要爬取的页面非常多的时候,单个主机的处理能力就不能满足我们的需求了(无论是处理速度还是网络请求的并发数),这时候分布式爬虫的优势就显现出来. 而Scrapy-Redis则是一个基于Redis的Scrapy分布式组件.它利用Redis对用于爬取的请求(Requests)进行存储和调度(Schedule),并对爬取产生的项目(items)存储以供后续处理使用.scrapy-redi

  • scrapy-redis分布式爬虫的搭建过程(理论篇)

    1. 背景 Scrapy 是一个通用的爬虫框架,但是不支持分布式,Scrapy-redis是为了更方便地实现Scrapy分布式爬取,而提供了一些以redis为基础的组件(仅有组件). 2. 环境 系统:win7 scrapy-redis redis 3.0.5 python 3.6.1 3. 原理 3.1. 对比一下scrapy 和 Scrapy-redis 的架构图. scrapy架构图: scrapy-redis 架构图: 多了一个redis组件,主要影响两个地方:第一个是调度器.第二个是数

  • 详解Scrapy Redis入门实战

    简介 scrapy-redis是一个基于redis的scrapy组件,用于快速实现scrapy项目的分布式部署和数据爬取,其运行原理如下图所示. Scrapy-Redis特性 分布式爬取 你可以启动多个共享同一redis队列的爬虫实例,多个爬虫实例将各自提取到或者已请求的Requests在队列中统一进行登记,使得Scheduler在请求调度时能够对重复Requests进行过滤,即保证已经由某一个爬虫实例请求过的Request将不会再被其他的爬虫实例重复请求. 分布式数据处理 将scrapy爬取到

  • Python爬虫天气预报实例详解(小白入门)

    本文研究的主要是Python爬虫天气预报的相关内容,具体介绍如下. 这次要爬的站点是这个:http://www.weather.com.cn/forecast/ 要求是把你所在城市过去一年的历史数据爬出来. 分析网站 首先来到目标数据的网页 http://www.weather.com.cn/weather40d/101280701.shtml 我们可以看到,我们需要的天气数据都是放在图表上的,在切换月份的时候,发现只有部分页面刷新了,就是天气数据的那块,而URL没有变化. 这是因为网页前端使用

  • 详解SpringBoot Redis自适应配置(Cluster Standalone Sentinel)

    核心代码段 提供一个JedisConnectionFactory  根据配置来判断 单点 集群 还是哨兵 @Bean @ConditionalOnMissingBean public JedisConnectionFactory jedisConnectionFactory() { JedisConnectionFactory factory = null; String[] split = node.split(","); Set<HostAndPort> nodes =

  • 详解scrapy内置中间件的顺序

    1. 内置下载器中间件顺序 {'scrapy.downloadermiddlewares.ajaxcrawl.AjaxCrawlMiddleware': 560, 'scrapy.downloadermiddlewares.cookies.CookiesMiddleware': 700, 'scrapy.downloadermiddlewares.defaultheaders.DefaultHeadersMiddleware': 400, 'scrapy.downloadermiddleware

  • 详解基于redis实现分布式锁

    前言 为了保证一个在高并发存场景下只能被同一个线程操作,java并发处理提供ReentrantLock或Synchronized进行互斥控制.但是这仅仅对单机环境有效.我们实现分布式锁大概通过三种方式. redis实现分布式锁 数据库实现分布式锁 zk实现分布式锁 原理剖析 上述三种分布式锁都是通过各自为依据对各个请求进行上锁,解锁从而控制放行还是拒绝.redis锁是基于其提供的setnx命令. setnx当且仅当key不存在.若给定key已经存在,则setnx不做任何动作.setnx是一个原子

  • 详解基于redis实现的四种常见的限流策略

    目录 一.引言 二.固定时间窗口算法 三.滑动时间窗口算法 四.漏桶算法 五.令牌桶算法 一.引言 在web开发中功能是基石,除了功能以外运维和防护就是重头菜了.因为在网站运行期间可能会因为突然的访问量导致业务异常.也有可能遭受别人恶意攻击 所以我们的接口需要对流量进行限制.俗称的QPS也是对流量的一种描述 针对限流现在大多应该是令牌桶算法,因为它能保证更多的吞吐量.除了令牌桶算法还有他的前身漏桶算法和简单的计数算法 下面我们来看看这四种算法 二.固定时间窗口算法 固定时间窗口算法也可以叫做简单

  • C++中的STL中map用法详解(零基础入门)

    目录 一.什么是 map ? 二.map的定义 2.1 头文件 2.2 定义 2.3 方法 三.实例讲解 3.1 增加数据 3.2 删除数据 3.3 修改数据 3.4 查找数据 3.5 遍历元素 3.6 其它方法 四.总结 map 在编程中是经常使用的一个容器,本文来讲解一下 STL 中的 map,赶紧来看下吧! 一.什么是 map ? map 是具有唯一键值对的容器,通常使用红黑树实现. map 中的键值对是 key value 的形式,比如:每个身份证号对应一个人名(反过来不成立哦!),其中

  • 详解Java redis中缓存穿透 缓存击穿 雪崩三种现象以及解决方法

    目录 前言 一.缓存穿透 二.缓存击穿 三.雪崩现象 总结 前言 本文主要阐述redis中的三种现象 1.缓存穿透 2.缓存击穿 3.雪崩现象 本文主要说明本人对三种情况的理解,如果需要知道redis基础请查看其他博客,加油! 一.缓存穿透 理解:何为缓存穿透,先要了解穿透,这样有助于区分穿透和击穿,穿透就类似于伤害一点一点的累计,最终打到穿透的目的,类似于射手,一下一下普通攻击,最终杀死对方,先上图 先来描述一下缓存穿透的过程: 1.由于我们取数据的原则是先查询redis上,如果redis上有

  • Spring boot详解缓存redis实现定时过期方法

    目录 前言 添加依赖 添加配置 常规缓存 开启缓存 设置缓存空间 设置缓存 增加设置缓存过期时间 总结 后记 前言 使用redis进行缓存数据,是目前比较常用的缓存解决方案.常用的缓存形式有一下几种: 1.纯原生代码进行redis的增删改查,手工编写缓存工具类,由开发者在代码中进行调用. 优势:代码由实际使用的开发者进行维护,便于定制化的改造. 2.使用市场上已有的缓存工具,也就是大家常说的大佬的轮子 优势:方便快捷,提升开发效率 添加依赖 修改pom文件引入如下配置 <?xml version

  • SpringBoot详解整合Redis缓存方法

    目录 1.Spring Boot支持的缓存组件 2.基于注解的Redis缓存实现 3.基于API的Redis缓存实现 1.Spring Boot支持的缓存组件 在Spring Boot中,数据的缓存管理存储依赖于Spring框架中cache相关的org.springframework.cache.Cache和org.springframework.cache.CacheManager缓存管理器接口. 如果程序中没有定义类型为CacheManager的Bean组件或者是名为cacheResolve

随机推荐