爬虫从入门到精通(9) | Python-Scrapy爬虫框架入门

提前声明:该专栏涉及的所有案例均为学习使用,如有侵权,请联系本人删帖!

一、scrapy框架的介绍和安装

1.python安装scrapy模块

pip install scrapy

2.scrapy爬虫架构

  • Scrapy 是一个快速、高层次的基于 python 的 web 爬虫构架,它用于抓取web站点并从页面中提取结构化的数据。可以更容易构建大规模的抓取项目;
  • Scrapy 使用了 Twisted异步网络库来处理网络通讯。 异步处理请求,速度非常快。
  • Scrapy 常应用在包括数据挖掘,信息处理或存储历史数据等一系列的程序中。
  • Scrapy 可以使用自动调节机制自动调整爬行速度

二、第一个scrapy案例

第1步:安装好Scrapy模块后,cmd命令创建一个项目

scrapy startproject 项目名

第2步:创建好项目后,用pycharm打开项目

项目目录
在这里插入图片描述

第3步:在pycharm中的控制台创建一个爬虫spider

这里每个spider就相当于一个独立的爬虫脚本,域名可以随便输入一个,后期代码中可以进行更改

scrapy genspider spider_name 域名

在这里插入图片描述

第4步:在settings.py中,修改robots协议
在这里插入图片描述

第5步:在新建好的spider中,初始化start_urls列表

start_urls列表是该爬虫启动的时候,最先执行的爬虫,默认返回的爬虫response在parse函数中接收。
在这里插入图片描述

第6步:settings.py中添加请求头
在这里插入图片描述
如果要添加cookies的设置
在这里插入图片描述

第7步:在spider文件中的parse方法里测试是否能够获取到页面数据。

scrapy crawl 爬虫名 # 有日志启动
scrapy crawl 爬虫名 --nolog # 无日志启动

在这里插入图片描述
在这里插入图片描述

第8步:在items.py中,定义我们要爬取的字段是那些。
在这里插入图片描述

第9步:在spider中导item包,并在parse方法中实例化一个item
在这里插入图片描述
在这里插入图片描述

第10步:运行项目
取到xpath的列表后需要获取数据要使用的方法:

 response.xpath返回一个selector对象,此对象可继续调用xpath元素及其方法
 可以通过以下两个方法获取selector对象的字符串内容:
   Extract_first(),相当于text[0]
   Extract(),取出返回整个的list的么一个字符串内容

在这里插入图片描述

第11步:将数据保存到mongoDB中的操作步骤
将提取完全的item去yeild出来传入pipeline中间件
在这里插入图片描述
在这里插入图片描述
要使用popelines.py中的item,必须需要配置
在这里插入图片描述
在items.py中重新插入一个字段,加此字段是因为hash查询速度快且唯一
在这里插入图片描述

在popelines.py加入以下代码

import pymongo, hashlib


class MaoyanPipeline(object):
    def __init__(self):
        self.client = pymongo.MongoClient()
        self.db = self.client['maoyan']

    def get_md5(self, value):  # hash查找更快
        md5 = hashlib.md5()
        md5.update(value.encode('utf-8'))
        return md5.hexdigest()

    def process_item(self, item, spider):
        item['detail_hash'] = self.get_md5(item['detail_url'])
        self.db['movie'].update({'detail_hash': item['detail_hash']}, {'$set': dict(item)}, True)
        return item

查询数据库是否有数据
在这里插入图片描述

三、start_requests方法

使用start_requests方法,也可以替换默认的启动
优点:可以手动的设置初始url的一些request信息,比如可以自带meta参数,比如可以给他收到设置一些请求头。
在这里插入图片描述

四、配置文件settings.py的详细介绍

#==>第一部分:基本配置<===
#1、项目名称,默认的USER_AGENT由它来构成,也作为日志记录的日志名
BOT_NAME = 'Amazon'

#2、爬虫应用路径
SPIDER_MODULES = ['Amazon.spiders']
NEWSPIDER_MODULE = 'Amazon.spiders'

#3、客户端User-Agent请求头
#USER_AGENT = 'Amazon (+http://www.yourdomain.com)'

#4、是否遵循爬虫协议
# Obey robots.txt rules
ROBOTSTXT_OBEY = False

#5、是否支持cookie,cookiejar进行操作cookie,默认开启,一般请求页面会携带上一次的cookie
#COOKIES_ENABLED = False

#6、Telnet用于查看当前爬虫的信息,操作爬虫等...使用telnet ip port ,然后通过命令操作
#TELNETCONSOLE_ENABLED = False
#TELNETCONSOLE_HOST = '127.0.0.1'
#TELNETCONSOLE_PORT = [6023,]

#7、Scrapy发送HTTP请求默认使用的请求头
#DEFAULT_REQUEST_HEADERS = {
#   'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
#   'Accept-Language': 'en',
#}



#===>第二部分:并发与延迟<===
#1、下载器总共最大处理的并发请求数,默认值16
#CONCURRENT_REQUESTS = 32

#2、每个域名能够被执行的最大并发请求数目,默认值8
#CONCURRENT_REQUESTS_PER_DOMAIN = 16

#3、能够被单个IP处理的并发请求数,默认值0,代表无限制,需要注意两点
#I、如果不为零,那CONCURRENT_REQUESTS_PER_DOMAIN将被忽略,即并发数的限制是按照每个IP来计算,而不是每个域名
#II、该设置也影响DOWNLOAD_DELAY,如果该值不为零,那么DOWNLOAD_DELAY下载延迟是限制每个IP而不是每个域
#CONCURRENT_REQUESTS_PER_IP = 16

#4、如果没有开启智能限速,这个值就代表一个规定死的值,代表对同一网址延迟请求的秒数
#DOWNLOAD_DELAY = 3



#===>第三部分:智能限速/自动节流:AutoThrottle extension<===
#一:介绍
from scrapy.contrib.throttle import AutoThrottle #http://scrapy.readthedocs.io/en/latest/topics/autothrottle.html#topics-autothrottle
设置目标:
1、比使用默认的下载延迟对站点更好
2、自动调整scrapy到最佳的爬取速度,所以用户无需自己调整下载延迟到最佳状态。用户只需要定义允许最大并发的请求,剩下的事情由该扩展组件自动完成


#二:如何实现?
在Scrapy中,下载延迟是通过计算建立TCP连接到接收到HTTP包头(header)之间的时间来测量的。
注意,由于Scrapy可能在忙着处理spider的回调函数或者无法下载,因此在合作的多任务环境下准确测量这些延迟是十分苦难的。 不过,这些延迟仍然是对Scrapy(甚至是服务器)繁忙程度的合理测量,而这扩展就是以此为前提进行编写的。


#三:限速算法
自动限速算法基于以下规则调整下载延迟
#1、spiders开始时的下载延迟是基于AUTOTHROTTLE_START_DELAY的值
#2、当收到一个response,对目标站点的下载延迟=收到响应的延迟时间/AUTOTHROTTLE_TARGET_CONCURRENCY
#3、下一次请求的下载延迟就被设置成:对目标站点下载延迟时间和过去的下载延迟时间的平均值
#4、没有达到200个response则不允许降低延迟
#5、下载延迟不能变的比DOWNLOAD_DELAY更低或者比AUTOTHROTTLE_MAX_DELAY更高

#四:配置使用
#开启True,默认False
AUTOTHROTTLE_ENABLED = True
#起始的延迟
AUTOTHROTTLE_START_DELAY = 5
#最小延迟
DOWNLOAD_DELAY = 3
#最大延迟
AUTOTHROTTLE_MAX_DELAY = 10
#每秒并发请求数的平均值,不能高于 CONCURRENT_REQUESTS_PER_DOMAIN或CONCURRENT_REQUESTS_PER_IP,调高了则吞吐量增大强奸目标站点,调低了则对目标站点更加”礼貌“
#每个特定的时间点,scrapy并发请求的数目都可能高于或低于该值,这是爬虫视图达到的建议值而不是硬限制
AUTOTHROTTLE_TARGET_CONCURRENCY = 16.0
#调试
AUTOTHROTTLE_DEBUG = True
CONCURRENT_REQUESTS_PER_DOMAIN = 16
CONCURRENT_REQUESTS_PER_IP = 16



#===>第四部分:爬取深度与爬取方式<===
#1、爬虫允许的最大深度,可以通过meta查看当前深度;0表示无深度
# DEPTH_LIMIT = 3

#2、爬取时,0表示深度优先Lifo(默认);1表示广度优先FiFo

# 后进先出,深度优先
# DEPTH_PRIORITY = 0
# SCHEDULER_DISK_QUEUE = 'scrapy.squeue.PickleLifoDiskQueue'
# SCHEDULER_MEMORY_QUEUE = 'scrapy.squeue.LifoMemoryQueue'
# 先进先出,广度优先

# DEPTH_PRIORITY = 1
# SCHEDULER_DISK_QUEUE = 'scrapy.squeue.PickleFifoDiskQueue'
# SCHEDULER_MEMORY_QUEUE = 'scrapy.squeue.FifoMemoryQueue'


#3、调度器队列
# SCHEDULER = 'scrapy.core.scheduler.Scheduler'
# from scrapy.core.scheduler import Scheduler

#4、访问URL去重
# DUPEFILTER_CLASS = 'step8_king.duplication.RepeatUrl'



#===>第五部分:中间件、Pipelines、扩展<===
# 爬虫中间件,前边为地址,后变为优先级,越小越先启动
SPIDER_MIDDLEWARES = {
   'guba_scrapy.middlewares.GubaScrapySpiderMiddleware': 543,
}

# 下载中间件,前边为地址,后变为优先级,越小越先启动
DOWNLOADER_MIDDLEWARES = {
   'guba_scrapy.middlewares.GubaScrapyDownloaderMiddleware': 543,
}

# 插件
EXTENSIONS = {
   'scrapy.extensions.telnet.TelnetConsole': None,
}

# 管道中间件,前边为地址,后变为优先级,越小越先启动
ITEM_PIPELINES = {
    'guba_scrapy.pipelines.GubaScrapyPipeline': 300,
}



#===>第六部分:缓存<===
"""
1. 启用缓存
    目的用于将已经发送的请求或相应缓存下来,以便以后使用
    
    from scrapy.downloadermiddlewares.httpcache import HttpCacheMiddleware
    from scrapy.extensions.httpcache import DummyPolicy
    from scrapy.extensions.httpcache import FilesystemCacheStorage
"""
# 是否启用缓存策略
# HTTPCACHE_ENABLED = True

# 缓存策略:所有请求均缓存,下次在请求直接访问原来的缓存即可
# HTTPCACHE_POLICY = "scrapy.extensions.httpcache.DummyPolicy"
# 缓存策略:根据Http响应头:Cache-Control、Last-Modified 等进行缓存的策略
# HTTPCACHE_POLICY = "scrapy.extensions.httpcache.RFC2616Policy"

# 缓存超时时间
# HTTPCACHE_EXPIRATION_SECS = 0

# 缓存保存路径
# HTTPCACHE_DIR = 'httpcache'

# 缓存忽略的Http状态码
# HTTPCACHE_IGNORE_HTTP_CODES = []

# 缓存存储的插件
# HTTPCACHE_STORAGE = 'scrapy.extensions.httpcache.FilesystemCacheStorage'


五、Scrapy的组件及其运行流程

在这里插入图片描述
运行流程:

  • 引擎:Hi!Spider, 你要处理哪一个网站?
  • Spider:老大要我处理xxxx.com。
  • 引擎:你把第一个需要处理的URL给我吧。
  • Spider:给你,第一个URL是xxxxxxx.com。
  • 引擎:Hi!调度器,我这有request请求你帮我排序入队一下。
  • 调度器:好的,正在处理你等一下。
  • 引擎:Hi!调度器,把你处理好的request请求给我。
  • 调度器:给你,这是我处理好的request
  • 引擎:Hi!下载器,你按照老大的下载中间件的设置帮我下载一下这个request请求
  • 下载器:好的!给你,这是下载好的东西。(如果失败:sorry,这个request下载失败了。然后引擎告诉调度器,这个request下载失败了,你记录一下,我们待会儿再下载)
  • 引擎:Hi!Spider,这是下载好的东西,并且已经按照老大的下载中间件处理过了,你自己处理一下(注意!这儿responses默认是交给def parse()这个函数处理的)
  • Spider:(处理完毕数据之后对于需要跟进的URL),Hi!引擎,我这里有两个结果,这个是我需要跟进的URL,还有这个是我获取到的Item数据。
  • 引擎:Hi !管道 我这儿有个item你帮我处理一下!调度器!这是需要跟进URL你帮我处理下。然后从第四步开始循环,直到获取完老大需要全部信息。
  • 管道调度器:好的,现在就做!

注意!只有当调度器中不存在任何request了,整个程序才会停止,(也就是说,对于下载失败的URL,Scrapy也会重新下载。)

六、管道文件pipeline

1.pipeline的作用

  • 清理html数据
  • 验证爬取的数据
  • 去重并丢弃
  • 将爬取的结果保存到数据库中或文件中

2.简单使用一下管道pipeline

例如我们有个baidu_spider爬虫

import scrapy

class BaiduSpiderSpider(scrapy.Spider):
    name = 'baidu_spider'
    allowed_domains = []
    start_urls = ['http://www.baidu.com']

    def parse(self, response):
        item = {}
        item['url'] = response.url
        return item

然后我们在pipelines.py 文件中输出一下这个item

from itemadapter import ItemAdapter

class GubaScrapyPipeline:
    def process_item(self, item, spider):
        print(item)
        return item

想要管道文件生效,需要配置一下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DyfSxzuy-1596811101114)(C:\Users\qinfan\AppData\Roaming\Typora\typora-user-images\1596802679509.png)]

运行一下:

scrapy crawl baidu_spider --nolog

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Xk51DlbP-1596811101116)(C:\Users\qinfan\AppData\Roaming\Typora\typora-user-images\1596802700961.png)]

成功输出结果,说明我们的爬虫文件的item成功传入了管道文件!

3.管道文件的多个类

问题:一个管道文件有多个管道类,如何能让item在不同类中传递呢?

添加一个管道类,修改管道文件。每个管道类中return item的意思是将处理过的item传给下一个管道类,如果不写return,那么下一个管道文件会处理空值。

from itemadapter import ItemAdapter


class GubaScrapyPipeline:
    def process_item(self, item, spider):
        print('我进入了管道类GubaScrapyPipeline')
        return item

class GubaScrapyPipeline11111:
    def process_item(self, item, spider):
        print('我进入了管道类GubaScrapyPipeline111')
        return item

修改配置文件,每个类后边的数字代表优先级,越小越先执行

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ur63EHa3-1596811101116)(C:\Users\qinfan\AppData\Roaming\Typora\typora-user-images\1596803091650.png)]

运行一下

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-n3NRSUyZ-1596811101119)(C:\Users\qinfan\AppData\Roaming\Typora\typora-user-images\1596803135272.png)]

4.多个爬虫文件如何使用管道文件

问题:我们scrapy项目中一般会有多个爬虫项目,但是一般管道文件只有一个,那么当不同爬虫文件的item进入管道中,那么我们如何处理呢?

方法一:

假设我们有两个爬虫文件

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gmdCRSj9-1596811101120)(C:\Users\qinfan\AppData\Roaming\Typora\typora-user-images\1596803409924.png)]

为了区分管道item,我们在各自的爬虫里加入一个特殊的字段

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QY14yOaq-1596811101122)(C:\Users\qinfan\AppData\Roaming\Typora\typora-user-images\1596803494482.png)]

管道文件修改为

from itemadapter import ItemAdapter


class GubaScrapyPipeline:
    def process_item(self, item, spider):
        if item['from_spider']=='baidu_spider':
            print('我是处理百度爬虫的管道类')
        return item

class GubaScrapyPipeline111:
    def process_item(self, item, spider):
        if item['from_spider'] == 'tencent_spider':
            print('我是处理腾讯爬虫的管道类')
        return item

方法二:

我们管道文件也可以对每个来源的爬虫进行判断

from itemadapter import ItemAdapter


class GubaScrapyPipeline:
    def process_item(self, item, spider):
        if spider.name == 'baidu_spider':
            print('我是处理百度爬虫的管道类')
        return item


class GubaScrapyPipeline111:
    def process_item(self, item, spider):
        if spider.name == 'tencent_spider':
            print('我是处理腾讯爬虫的管道类')
        return item

5.管道中的其他方法

open_spider(self,spider)
表示当spider被开启的时候调用这个方法

close_spider(self,spider)
当spider挂去年比时候这个方法被调用

from_crawler(cls,crawler)
这个可以用于获取settings配置文件中的信息,需要注意的这个是一个类方法,用法例子如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MVCYPxUX-1596877486180)(C:\Users\qinfan\AppData\Roaming\Typora\typora-user-images\1596877225499.png)]

6.一些item pipeline的使用例子

例子1
这个例子是将item写入到json文件中

import json

class JsonWriterPipeline(object):

    def __init__(self):
        self.file = open('items.jl', 'wb')

    def process_item(self, item, spider):
        line = json.dumps(dict(item)) + "\n"
        self.file.write(line)
        return item</pre>

例子2
将item写入到MongoDB,同时这里演示了from_crawler的用法

import pymongo

class MongoPipeline(object):

    collection_name = 'scrapy_items'

    def __init__(self, mongo_uri, mongo_db):
        self.mongo_uri = mongo_uri
        self.mongo_db = mongo_db

    @classmethod
    def from_crawler(cls, crawler):
        return cls(
            mongo_uri=crawler.settings.get('MONGO_URI'),
            mongo_db=crawler.settings.get('MONGO_DATABASE', 'items')
        )

    def open_spider(self, spider):
        self.client = pymongo.MongoClient(self.mongo_uri)
        self.db = self.client[self.mongo_db]

    def close_spider(self, spider):
        self.client.close()

    def process_item(self, item, spider):
        self.db[self.collection_name].insert(dict(item))
        return item</pre>

例子3:去重
一个用于去重的过滤器,丢弃那些已经被处理过的item,假设item有一个唯一的id,但是我们spider返回的多个item中包含了相同的id,去重方法如下:这里初始化了一个集合,每次判断id是否在集合中已经存在,从而做到去重的功能

from scrapy.exceptions import DropItem

class DuplicatesPipeline(object):

    def __init__(self):
        self.ids_seen = set()

    def process_item(self, item, spider):
        if item['id'] in self.ids_seen:
            raise DropItem("Duplicate item found: %s" % item)
        else:
            self.ids_seen.add(item['id'])
            return item</pre>

7.注意事项

  • 使用管道,必须要在settings.py文件中进行配置
  • 配置文件中的管道配置时候的数字代表优先级,越小越先执行
  • 管道类中的item传递必须通过return
  • 管道类中的process_item(self, item, spider)才可以接收传过来的item,其他方法不可以
  • 管道的作用一般就是处理接收过来的item,或者将接收的item存入数据库
  • spider将值传入管道文件通过return,但是return的时候不可以retrun列表,一般就是字典

七、下载中间件middleware

1.常用的下载中间件方法

 class RenrenDownloaderMiddleware:
     def process_request(self, request, spider):
         # 当每个request请求通过下载中间件时候调用的,可以不返回值,比如我们就单单的使用随机useragent和proxy时候
         return None

     def process_response(self, request, response, spider):
          # 当我们下载器从网页上下载完http请求,调用的方法,必须要返回一个响应传给spider
          return response
        
     def process_exception(self, request, exception, spider):
          #处理在使用下载器中间时候遇到的异常
          pass

2.使用下载中间件写一个随机user-agent

问题:有时候我们爬取一个网站爬取太频繁,可能网站会通过判断user-agent判断是不是一个爬虫,我们因此可以通过随机user-agent来避免这种情况

1.在setting.py 加入我们的user-agent列表

USER_AGENT_LIST = [
            'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.835.163 Safari/535.1',
            'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:6.0) Gecko/20100101 Firefox/6.0',
            'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.50 (KHTML, like Gecko) Version/5.1 Safari/534.50',
            'Opera/9.80 (Windows NT 6.1; U; zh-cn) Presto/2.9.168 Version/11.50',
            'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0; .NET CLR 2.0.50727; SLCC2; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; InfoPath.3; .NET4.0C; Tablet PC 2.0; .NET4.0E)',
            'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; InfoPath.3; .NET4.0C; .NET4.0E; SE 2.X MetaSr 1.0)'
        ]

2.在下载中间件middlewares.py文件中随机选择一个user-agent

import random

class RandomUserAgentMiddleware:
	def process_request(self, request, spider):
		ua=random.choice(self.settings.USER_AGENT_LIST)
        request.headers["User-Agent"]=ua

3.在settings中启用下载中间件

DOWNLOADER_MIDDLEWARES = {
   'renren.middlewares.RandomUserAgentMiddleware': 543,
}

4.在spider.py中输出看一下
在这里插入图片描述

结果:
在这里插入图片描述

3.使用下载中间件写代理IP

步骤:

  • 首先准备一些代理IP
  • 一般我们对代理IP会有一个验证的过程,假设有一个代理IP的列表,定义一个函数,如果代理ip可以通过则没事,当代理IP不通过删除该代理IP,然后再进行正常的爬虫
  • 然后写下载中间件,此处知识假设,真实不可能只有一个代理IP,一般是从代理ip列表随机选择
  • 配置文件中激活下载中间件

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OWIrfRD4-1596900041972)(C:\Users\qinfan\AppData\Roaming\Typora\typora-user-images\1596899619275.png)]

八、scrapy-redis分布式

1.scrapy-redis分布式

首先了解什么是分布式?

将一个任务分割为多份,每一份由一个计算机完成,最后所有的计算机能够成为一个整体,成为这个任务的结果

在了解下分布式爬虫

即多台电脑爬取同一个项目。原来的项目都是部署在一台电脑上的,爬取速度虽然快,但是我们还能提升,联想到分布式,我们可以通过多台电脑进行配合爬取,这样我们的爬取速度就可以大幅度提升。

那Scrapy-redis的原理

  • Master端:核心服务器,搭建Redis数据库,不负责爬取,只负责url指纹判断是否重复、request的分配、以及数据的存储
  • Slaver端::爬虫程序执行端,负责执行爬虫程序,运行过程中提交新的request给Master
    在这里插入图片描述

首先Slaver端从Master端拿任务(request, url)进行数据爬取,Slaver抓取数据的同时,产生新的request就提交给Master进行处理。
Master端只有一个Redis数据库,负责将未处理的request去重和任务分配,将处理后的request加入待爬取的队列,并且存储爬取的数据

scrapy和scrapy-redis的区别

  1. scrapy是一个爬虫框架,它不支持分布式
  2. scrapy-redis通过scrapy增加一个redis组件,这个组件里设置了待爬取url的列表和每个url

2.scrapy-redis拓展组件

上边刚说 scrapy-redis比Scrapy增加了组件,那么介绍下组件

组件作用
SchedulerScrapy改造了python本来的双向队列形成了自己的Scrapy队列,但是Scrapy多个spider不能共享待爬取队列, 即Scrapy本身不支持爬虫分布式。scrapy-redis 的解决是把这个待爬取队列换成redis数据库,从同一个redis队列存放要爬取的request,便能让多个spider去同一个数据库里读取。
Duplication FilterScrapy中用集合实现这个request去重功能,Scrapy中把已经发送的request指纹放入到一个集合中,把下一个request的指纹拿到集合中比对,如果该指纹存在于集合中,说明这个request发送过了,如果没有则继续操作。 在scrapy-redis中去重是由Duplication Filter组件来实现的,它通过redis的set 不重复的特性,巧妙的实现了Duplication Filter去重。scrapy-redis调度器从引擎接受request,将request的指纹存⼊redis的set检查是否重复,并将不重复的请求push到redis的 请求队列。
Item Pipelinescrapy-redis 的Item Pipeline将爬取到的 Item 存⼊redis的 items queue。修改过Item Pipeline可以很方便的根据 key 从 items queue 提取item,从⽽实现items processes集群。
Base Spider不再使用scrapy原有的Spider类,重写的RedisSpider继承了Spider和RedisMixin这两个类,RedisMixin是用来从redis读取url的类。 该类可以去连接数据库,其他中的两个函数一个是可以使爬虫一直处于活跃状态不关闭,另一个函数可以再处理一个请求后再去寻找下一个请求

3.scrapy-redis架构

在这里插入图片描述

  1. master端将待爬取的请求放入redis后,其他爬虫端开始执行
  2. 首先调度器从redis队列中拿到请求返回给引擎,再通过下载器中间件到下载器
  3. 下载器下载后将数据返回给引擎,再到spiders
  4. spiders一方面继续让引擎去调度器拿请求重复该过程,另一方面将获取的数据交给管道
  5. 管道将数据处理后存入redis的指定item队列

4.使用Scrapy-redis分布式的步骤

第一步:继承新类

在这里插入图片描述

第二步:注释start_urls,新建py文件,将url存储到redis,设置任务

在这里插入图片描述

第三步:在spider中增加一个类变量redis_key

第四步:在settings.py进行配置

主机:

# 配置scrapy-redis调度器
SCHEDULER = "scrapy_redis.scheduler.Scheduler"
# 配置url去重
DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"
ITEM_PIPELINES = {
'scrapy_redis.pipelines.RedisPipeline': 300
}
# 优先级队列
SCHEDULER_QUEUE_CLASS = 'scrapy_redis.queue.PriorityQueue'
# 主机名
REDIS_HOST = 'localhost'
# 端口号
REDIS_PORT = 6379

从机:

1.将start_urls初始化的代码全部注释
2.从机的redis可以关闭

SCHEDULER = "scrapy_redis.scheduler.Scheduler"
# 去重
DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"
# 优先级队列
SCHEDULER_QUEUE_CLASS = 'scrapy_redis.queue.PriorityQueue'

# ITEM_PIPELINES = {
#     'scrapy_redis.pipelines.RedisPipeline': 300
# }

REDIS_HOST = '主机ip'
REDIS_PORT = 6379
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

张烫麻辣亮。

谢谢老板,祝你生8个儿子!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值