Scrapy框架之分布式操作

Stella981
• 阅读 727

一、分布式爬虫介绍

  分布式爬虫概念:多台机器上执行同一个爬虫程序,实现网站数据的分布爬取。

1、原生的Scrapy无法实现分布式爬虫的原因?

  • 调度器无法在多台机器间共享:因为多台机器上部署的scrapy会各自拥有各自的调度器,这样就使得多台机器无法分配start_urls列表中的url。
  • 管道无法给多台机器共享:多台机器爬取到的数据无法通过同一个管道对数据进行统一的数据持久出存储。

2、scrapy-redis组件

  scrapy-redis是专门为scrapy框架开发的一套组件。该组件可以解决上述两个问题,让Scrapy实现分布式。   组件安装:

$ pip3 intall scrapy-redis

二、基于RedisCrawlSpider的分布式爬取

1、redis配置和启动

(1)对redis配置文件redis.conf进行配置

  • 注释该行:bind 127.0.0.1,表示可以让其他ip访问redis

  • 将yes该为no:protected-mode no,表示可以让其他ip操作redis

    不注释时,只允许本机的客户端连接

    bind 127.0.0.1

    yes改为no,关闭redis的保护模式,客户端可以对服务器进行读写操作

    protected-mode no

(2)基于配置文件开启redis服务器

# MAC/Linux
$ pwd
/Users/hqs/redis-5.0.2
$ src/redis-server redis.conf 

# windows
$ redis-server.exe redis-windows.conf

2、项目和爬虫创建

$ scrapy startproject redisPro
$ cd redisPro/
$ scrapy genspider -t crawl qiubai www.qiushibaike.com/pic/

  这里运用CrawlSpider创建爬虫文件爬取全站图片数据。

3、爬虫文件编写

import scrapy
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule
from scrapy_redis.spiders import RedisCrawlSpider
from redisPro.items import RedisproItem    # 引入items类


class QiubaiSpider(RedisCrawlSpider):
    name = 'qiubai'
    # allowed_domains = ['www.qiushibaike.com/pic/']
    # start_urls = ['http://www.qiushibaike.com/pic/']
    # redis_key表示调度器中的队列(将要爬取的页面数据对应的url都需要放置到调度器队列中)
    redis_key = 'qiubaispider'   # 自定义调度器队列的名称,该行代码表示的含义和start_urls一样

    # 链接提取器
    # 从页面提取链接页码的url:/pic/page/2?s=5147462
    # s后对应的参数值会在浏览器刷新时动态变化, 正则忽略s参数的变化进行提取
    link = LinkExtractor(allow=r'/pic/page/\d+')
    # 规则解析器
    rules = (
        Rule(link, callback='parse_item', follow=True),
    )

    def parse_item(self, response):
        """解析操作:提取图片链接"""
        div_list = response.xpath('//div[@id="content-left"]/div')    # 获取divz列表
        for div in div_list:    # 遍历div列表
            # 解析提取div中图片url,保存在img标签的src属性下
            img_url = "https:" + div.xpath('.//div[@class="thumb"]/a/img/@src').extract_first()
            # 实例化items对象
            item = RedisproItem()
            item['img_url'] = img_url    # 封装items

            yield item

(1)引入scrapy-redis中的模块

  在爬虫文件中要导入RedisCrawlSpider类,然后将爬虫文件修改成基于该类的源文件。

from scrapy_redis.spiders import RedisCrawlSpider

# class QiubaiSpider(CrawlSpider):
class QiubaiSpider(RedisCrawlSpider):

(2)声明redis_key属性

  redis_key表示调度器中的队列(将要爬取的页面数据对应的url都需要放置到调度器队列中)。   redis_key自定义调度器队列的名称,表示的含义和start_urls一样,因此需要将原来的start_url注释掉。

class QiubaiSpider(RedisCrawlSpider):
    name = 'qiubai'
    # allowed_domains = ['www.qiushibaike.com/pic/']
    # start_urls = ['http://www.qiushibaike.com/pic//']
    # redis_key表示调度器中的队列(将要爬取的页面数据对应的url都需要放置到调度器队列中)
    redis_key = 'qiubaispider'   # 自定义调度器队列的名称,该行代码表示的含义和start_urls一样

(3)链接提取器和规则解析器定义

class QiubaiSpider(RedisCrawlSpider)
    """代码省略"""    
    # 链接提取器
    # 从页面提取链接页码的url:/pic/page/2?s=5147462
    # s后对应的参数值会在浏览器刷新时动态变化, 正则忽略s参数的变化进行提取
    link = LinkExtractor(allow=r'/pic/page/\d+')
    # 规则解析器
    rules = (
        Rule(link, callback='parse_item', follow=True),
    )

(4)items.py编写和爬虫引入调用

import scrapy

class RedisproItem(scrapy.Item):
    # define the fields for your item here like:
    # name = scrapy.Field()
    img_url =scrapy.Field()

4、settings.py配置修改

(1)使用scrapy-redis组件中封装好的管道

  使用scrapy-redis组件中封装好的可以被共享的管道。   可以将每台机器爬取到的数据存储通过该管道存储到redis数据库中,从而实现了多台机器的管道共享。

# Configure item pipelines
# See https://doc.scrapy.org/en/latest/topics/item-pipeline.html
ITEM_PIPELINES = {
    # 'redisPro.pipelines.RedisproPipeline': 300,
    'scrapy_redis.pipelines.RedisPipeline': 400,
}

(2)使用scrapy-redis组件中封装好的调度器

  使用scrapy-redis组件中封装好的调度器,将所有的url存储到该指定的调度器中,从而实现了多台机器的调度器共享。   以下代码可在settings.py中任意位置粘贴:

# 使用scrapy-redis组件的去重队列
DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"
# 使用scrapy-redis组件自己的调度器
SCHEDULER = "scrapy_redis.scheduler.Scheduler"   # 核心配置
# 是否允许暂停
SCHEDULER_PERSIST = True   # 值为True表示:宕机恢复服务时,从宕机的那个地方开始爬取,不用从头开始

(3)爬虫程序不在redis本机时,指定redis地址

  管道默认会连接且将数据存储到本机的redis服务中,如果想要连接存储到其他redis服务中需要在settings.py中进行如下配置

# 如果redis服务器不在自己本机,则需要做如下配置
REDIS_HOST = '192.168.31.31' # redis服务的ip地址
REDIS_PORT = 6379
# 可选配置
# REDIS_ENCODING = 'utf-8'
# REDIS_PARAMS = {'password':'123456'}

(4)修改ua和关闭robots协议

# Crawl responsibly by identifying yourself (and your website) on the user-agent
USER_AGENT = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36' # 伪装请求载体身份

# Obey robots.txt rules
ROBOTSTXT_OBEY = False   # 不遵从门户网站robots协议,避免某些信息爬取不到

5、执行爬虫程序

  执行爬虫程序的方式与之前不同。   格式:lpush 队列名称(redis-key) 起始url

$ pwd
/Users/hqs/ScrapyProjects/redisPro/redisPro/spiders
$ scrapy runspider qiubai.py
.......
2018-12-08 12:04:34 [scrapy.extensions.telnet] DEBUG: Telnet console listening on 127.0.0.1:6023

  然后需要在redis客户端中,将起始url扔到调度器队列中:

$ src/redis-cli 
127.0.0.1:6379> lpush qiubaispider https://www.qiushibaike.com/pic/    # 将url扔入队列
(integer) 1

  查看reids中保存的爬取数据:

127.0.0.1:6379> keys *
1) "qiubai:items"
2) "data"
3) "name"
4) "qiubai:dupefilter"
127.0.0.1:6379> lrange qiubai:items 0 -1
   1) "{\"img_url\": \"https://pic.qiushibaike.com/system/pictures/12132/121326116/medium/FO4Z7Q83NXSOPYTL.jpg\"}"
   ......
点赞
收藏
评论区
推荐文章
blmius blmius
2年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Jacquelyn38 Jacquelyn38
3年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
待兔 待兔
4天前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Stella981 Stella981
2年前
Crawlscrapy分布式爬虫
1.概念:多台机器上可以执行同一个爬虫程序,实现网站数据的分布爬取2.原生的scrapy是不可以实现分布式式爬虫  a)调度器无法共享  b)管道无法共享3.scrapyredis组件:专门为scrapy开发的一套组件,该组件可以让scrapy实现分布式  a)pipinstallscrapyredis4.分布式爬取的流程:
Stella981 Stella981
2年前
Nginx + lua +[memcached,redis]
精品案例1、Nginxluamemcached,redis实现网站灰度发布2、分库分表/基于Leaf组件实现的全球唯一ID(非UUID)3、Redis独立数据监控,实现订单超时操作/MQ死信操作SelectPollEpollReactor模型4、分布式任务调试Quartz应用
Easter79 Easter79
2年前
Twitter的分布式自增ID算法snowflake (Java版)
概述分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的。有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。而twitter的snowflake解决了这种需求,最初Twitter把存储系统从MySQL迁移
Stella981 Stella981
2年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Wesley13 Wesley13
2年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
5个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这