天天看点

scrapy分布式爬虫

scrapy_redis

scrapy是一个通用的爬虫框架,但是不支持分布式,scrapy_redis是为了更方便的实现scrapy分布式爬取,而提供了一些以redis为基础的组件(仅有组件)。

scrapy_redis工作原理:

  1. 调度器将不再负责Url的调度,而是将url上传给scrapy_redis组件,由组件负责组织、去重
  2. redis组件会通过指纹(key)来进行去重操作,并且把请求对象分发给不同的客户端
  3. 客户端拿到请求对象后,再交给引擎–下载器
  4. pipeline不再负责本地化操作,而是把数据交给redis组件来负责写入redis数据库,达到资源共享、自动合并的目的

scrapy_redis组成:

Scheduler 调度器,scrapy本身不支持爬虫分布,scrapy_redis的解决是把这个scrapy queue换成redis数据库(也是指redis队列),从同一个redis-server存放要爬取的request,便能让多个spider去同一个数据库里读取。

Duplication Filter 指纹过滤器,scrapy用集合实现这个request去重功能,scrapy中把已经发送的request指纹放到一个集合中,把下一个request的指纹放到集合中比对,如果该指纹存在于集合中,说明这个request发送过了,如果没有则继续操作。

Item Pipeline 管道,引擎将(spider返回的)爬取到的item给Item Pipeline,scrapy_redis的Item Pipeline将爬取到的item存入redis的items pipeline。

Base Spider

分布式爬虫例子(爬取读书网的图书名称和封面图片链接,常规设置或者不需要修改的部分代码就没贴了):

# settings.py文件增加配置

# 去重类的引入
DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"
# redis调度器的引用
SCHEDULER = "scrapy_redis.scheduler.Scheduler"
# redis是否本地化的开关
SCHEDULER_PERSIST = True

# 分布式爬虫需要配置要访问的redis的主机
REDIS_HOST = '10.11.56.63'  # 主机ip
REDIS_PORT = 

ITEM_PIPELINES = {
   'dushuProject.pipelines.DushuprojectPipeline': ,

    # 导入依赖
   'scrapy_redis.pipelines.RedisPipeline':,
}

# 延时1s(反爬虫)
DOWMLOAD_DELAY = 
           
# items.py文件,即要爬取的数据字段

import scrapy
class DushuprojectItem(scrapy.Item):
    title = scrapy.Field()
    img_url = scrapy()
           
# pipelines.py文件,未作修改
class DushuprojectPipeline(object):
    def process_item(self, item, spider):
        return item
           
# read2.py文件(爬虫文件,读书网)

# -*- coding: utf-8 -*-
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import Rule
from scrapy_redis.spiders import RedisCrawlSpider  # 导入RedisCrawlSpider

class Read2Spider(RedisCrawlSpider):  # 继承的父类修改一下
    name = 'read2'  # 爬虫名字
    # start_urls = ['https://www.dushu.com/book/1081.html']  # 初始url

    # 键名称的一般规则  爬虫名字:start_urls
    redis_key = 'read2:start_urls'  # 由主机提供

    # 指定了页面内,链接的提取规则,会被父类自动调用
    rules = (
        Rule(LinkExtractor(allow=r'/book/1081_\d+.html'), callback='parse_item', follow=False),
    )

    # 页面数据解析函数
    # 可以自定义,只要保证callback的参数与这个函数名一致即可
    def parse_item(self, response):
        # 每页的图书列表
        book_list = response.xpath('//div[@class="bookslist"]//li')

        for each in book_list:
            i = {}
            i['title'] = each.xpath('.//h3//@title').extract_first()
            i['img_url'] = each.xpath('.//img/@src').extract_first()

            print(i)
            yield i
           
# 执行分布式爬虫的步骤:

# 1. 本地运行以下命令
scrapy runspider read2.py

# 2. 主机端开启redis服务
# 另开窗口
redis-cli
lpush redis_key start_url  # 推送start_url
# 例如 lpush read2:star_url "https://www.dushu.com/book/1081.html"
           

远程连接redis:

redis-cli -h ip -p 6379 -a password