爬虫随笔(3):scrapy-redis分布式爬虫

前言

学了两星期requests入门爬虫后,又学了一星期Scrapy。。

然后,我就被迫强上分布式爬爬虫了。。

也是应了一直以来我的学习心得,赶着DDL硬着头皮逼出来的,往往是学得最快的一个阶段。

还记得那天下午开始搞redis,网上其他大佬写的代码太高级没看懂,只好对着官方文档做些基础操作。搞到那天晚上11点多,分布式爬虫才总算动起来了,当晚一个通宵就把分布式爬虫框架做出来给组员整合代码。。

坑1:安装

事实上花了最多时间是在安装上。。

至今还在想我为什么会那么傻。。

为什么要在电脑上装那么多Python27。。

我要安装使用的是annaconda里自带的那个,结果我在CMD下装的东西总是跑到C盘里面那个去,包括之前的pip更新也是,只要是在CMD下执行的python ...命令全部被狗吃了似的。。刚才也是装到头皮发麻才去pycharm里面看了一下环境插件,才知道插件跑别的地方去了。环境变量都改了也没用,果断卸载,不带手软!

安装条件
  • Python2.7/3.4/3.5
  • Scrapy >= 1.0
  • Redis >= 2.8
  • redis-py >= 2.10
Redis安装

Redis官方并不支持Windows版本,但是官网上给出了一个微软提供的git地址

下载Redis-x64-3.2.100.msi双击安装,安装的时候建议添加到环境变量,设置数据库大小我直接用了500M。

接下来,在cmd下输入redis-cli就可以进行数据库操作了,这也说明redis安装成功了。

redis-py安装

只要你不是像我一样存在多个python的情况,一般你是可以直接按下述安装成功的:

先下载包:git地址

然后解压到python目录下,在该目录下运行python setup.py install

安装完成!

scrapy-redis安装

有了前面的依赖支撑,现在你可以轻松地安装:

pip install scrapy-redis

好了,你省了几小时的时间了。。

坑2:什么是redis来着?

Redis数据库安装完成后,我们可以通过CMD来控制,但更方便的还可以下载一个可视化管理工具RedisDesktopManager。

那么什么是Redis呢?接下来:

  • Step1:打开任意浏览器,在百度搜索栏输入“Redis”
  • Step2:点击蓝色的搜索按钮

好吧,如果你真的很懒->我可以容忍你的小偷懒

划重点:

  1. Key-Value数据库,提供多种语言的API(就是调用接口)。
  2. 支持存储的value类型相对更多,包括string(字符串)、list(链表)、set(集合)、zset(sorted set --有序集合)和hash(哈希类型),支持丰富的操作。
  3. redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并且在此基础上实现了 master-slave(主从) 同步。

简而言之,这就是一个数据库。那为什么我们要使用这个数据库,这还得说明一下分布式爬虫以及生产者消费模型。

坑3:生产者、消费者?

以上一篇中国经济网的应用场景为例,我们考虑一下两种运作方式:

肯德基模式

一般来说,我们爬虫的运作效率是像下面这样的,单线程,一个父URL处理成多个子URL再爬取数据完才开始处理下一个父URL。
爬虫的一般操作
这种方式的好处就是URL序列严格排列,数据处理井然有序。

麦当劳模式

现在考虑这样一种操作,一个线程/爬虫只负责处理父URL成子URL,接下来就不管了;剩下的部分由另一个线程来处理子URL。
分布式操作
这种方式支持了多线程爬虫,使得爬虫可以更加有效率地进行。而在这个模型中,父URL处理成子URL的进程可以成为生产者,而处理子URL的线程则是消费者。

分布式概念

上述分布式模型可以具现化为如下:
image

通过分离生产者、消费者并引入一个缓冲的连接池,这就形成了一个分布式爬虫系统。

Redis如何使用

综上,其实Redis使用在分布式爬虫中的作用就是这一个缓冲的连接池。在爬取过程中,生产者线程把父URL解析得到子URL后写入Redis数据库,消费者线程从数据库捕食任务。

也许你会问,这样跟保存在本地文件双线程跑有什么区别?区别就在于服务器,服务器是允许其它Machine访问的,这就可以实现:在Master-Machine上运行生产者,产生的子URL作为中间产物被众多Slave-Machine上的消费者线程消耗。

坑4:代码实现

好吧,正文开始hhh

首先还是大概看一遍官方文档吧:点我送官方文档哦

在这里建立Scrapy工程的时候就不要scrapy genspider example www.example.com这一步了,scrapy startproject cecn之后打开spiders文件夹,新建master.py和slave.py,接下来一样是在这里开始你的表演,不过根据基本法(官方文档)你还是要先写一些必要工作。

首先,settings.py中添加如下内容:

# 确保所有爬虫通过redis共享相同的重复过滤器
DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"
# 启用在redis中调度存储请求序列
SCHEDULER = "scrapy_redis.scheduler.Scheduler"
# 不要清理redis队列,允许暂停/恢复抓取
SCHEDULER_PERSIST = True
# 使用优先级队列调度请求
SCHEDULER_QUEUE_CLASS = 'scrapy_redis.queue.SpiderPriorityQueue'
REDIS_URL = None  # 一般情况可以省去
REDIS_HOST = 'localhost'  # 也可以根据情况改成 localhost
REDIS_PORT = 6379

items.py中添加如下内容:

# 开头添加
from sched import scheduler
from scrapy.loader import ItemLoader
from scrapy.loader.processors import MapCompose, TakeFirst, Join


class CecnItem(scrapy.Item):
    # [...as before...]


class CecnLoader(ItemLoader):
    default_item_class = CecnItem
    default_input_processor = MapCompose(lambda s: s.strip())
    default_output_processor = TakeFirst()
    description_out = Join()

pipelines.py和middlewares.py无需改动

接下来编写爬虫工程的核心——生产者/消费者

master.py

from scrapy_redis.spiders import RedisSpider
import redis


class MySpider(RedisSpider):

    name = 'produce'  # 生产者
    redis_key = 'MySpider:main_urls'  # 这个Key存放着父URL

    # 监听端口,一旦redis_key中传入了值便生成response,并回调parse()方法
    def __init__(self, *args, **kwargs):
        domain = kwargs.pop('domain', '')
        self.allowed_domains = filter(None, domain.split(','))
        super(MySpider, self).__init__(*args, **kwargs)


    def parse(self, response):
        # response这个对象包含了这个父URL页面的各项属性和数据
        son_xpath = '//'  # 子URL的xpath表达式
        urls = response.xpath(son_xpath)
        r = redis.Redis(host='localhost', port=6379, decode_responses=True)
        for url in urls:
            r.lpush('MySpider:start_urls', url)

slave.py

from scrapy_redis.spiders import RedisSpider
from cecn.items import CecnItem
import scrapy


class MySpider(RedisSpider):

    name = 'consume'  # 消费者
    redis_key = 'MySpider:start_urls'  # 存放二级页面

    # 监听端口,一旦redis_key中传入了值便生成response,并回调parse()方法
    def __init__(self, *args, **kwargs):
        domain = kwargs.pop('domain', '')
        self.allowed_domains = filter(None, domain.split(','))
        super(MySpider, self).__init__(*args, **kwargs)

    #信息提取,生成item
    def parse(self, response):
        # 页面元素定位
        yeild uitem

完成这两个部分,就可以开始运行测试了,在两个CMD窗口中分别运行

scrapy crawl produce & scrapy crawl consume

然后!!

。。。这两个爬虫就会一直停在那里listen…

这是因为此时MySpider:main_urls这个键里面没有任何值,爬虫缺少一个起始点。

你可以尝试在Python控制台运行:

r = redis.Redis(host='localhost', port=6379, decode_responses=True)
r.lpush(`MySpider:main_urls`, [a right main_url])

你就能看到你的两个爬虫都动起来啦!

蜘蛛从散养变成批发!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值