Python网络爬虫(scrapy-redis两种形式的分布式爬虫)

一、scrapy框架不能自己实现分布式爬虫的原因

  其一:因为多台机器上部署的scrapy会各自拥有各自的调度器,这样就使得多台机器无法分配start_urls列表中的url。(多台机器无法共享同一个调度器)

  其二:多台机器爬取到的数据无法通过同一个管道对数据进行统一的数据持久出存储。(多台机器无法共享同一个管道)

二、基于scrapy-redis组件作用

  其一:给原生的scrapy提供了可以被共享的调度器和管道
  其二:分布爬取的数据必须存储到redis中

三、scrapy-redis安装

# 安装scrapy-redis分布式爬虫组件
pip install scrapy-redis

四、基于scrapy-redis组件的分布式爬虫

  scrapy-redis组件中为我们封装好了可以被多台机器共享的调度器和管道,我们可以直接使用并实现分布式数据爬取。

  将爬虫类的父类修改成基于RedisSpider或者RedisCrawlSpider。

  注意:如果原始爬虫文件是基于Spider的,则应该将父类修改成RedisSpider,如果原始爬虫文件是基于CrawlSpider的,则应该将其父类修改成RedisCrawlSpider。

            - 注释或者删除start_urls列表,切加入redis_key属性,属性值为scrpy-redis组件中调度器队列的名称

  实现方式:

            1.基于该组件的RedisSpider类配置:爬虫文件

# -*- coding: utf-8 -*-
import scrapy
from ..items import WangyiproItem
from selenium import webdriver

# 配置scrapy-redis分布式
# 给原生的scrapy提供了可以被共享的调度器和管道
from scrapy_redis.spiders import RedisSpider

# 继承分布式爬虫类(RedisSpider)
class WangyiSpider(RedisSpider):
    name = 'wangyi'
    # allowed_domains = ['www.xx.com']
    # 在分布式爬虫中,不再需要指定起始url
    # start_urls = ['http://www.xx.com/']

    # 指定被共享的调度器队列的名称
    redis_key = "sunQueue"

    # 数据解析
    def parse(self, response):
        pass
    

  2.基于该组件的RedisCrawlSpider类配置:爬虫文件

# -*- coding: utf-8 -*-
import scrapy
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule
from fbssunPro.items import FbssunproItem

# 配置scrapy-redis分布式
# 给原生的scrapy提供了可以被共享的调度器和管道
from scrapy_redis.spiders import RedisCrawlSpider


# 继承分布式爬虫类(RedisCrawlSpider)
class SunSpider(RedisCrawlSpider):
    name = 'sun'
    # allowed_domains = ['www.xx.com']
    # 在分布式爬虫中,不再需要指定起始url
    # start_urls = ['http://www.xx.com/']

    # 指定被共享的调度器队列的名称
    redis_key = "sunQueue"

    # 规则解析器
    rules = (
        Rule(LinkExtractor(allow=r'正则表达式'), callback='parse_item', follow=True),
    )

    # 数据解析
    def parse_item(self, response):
        pass

  3.爬虫配置文件settings.py

#在配置文件中进行相关配置,开启使用scrapy-redis组件中封装好的调度器
# 使用scrapy-redis组件的去重队列
DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"
# 使用scrapy-redis组件自己的调度器
SCHEDULER = "scrapy_redis.scheduler.Scheduler"
# 是否允许暂停
SCHEDULER_PERSIST = True



#在配置文件中进行爬虫程序链接redis的配置:
REDIS_HOST = 'redis服务的ip地址'
REDIS_PORT = 6379
REDIS_ENCODING = ‘utf-8’
REDIS_PARAMS = {‘password’:’123456’}

五、基于scrapy-redis组件的redis数据库配置

  注意:scrapy-redis爬虫组件是基于redis数据库做数据持久化,不能是别的数据库

       修改redis启动配置文件:redis.windows.conf 

# redis.windows.conf配置:
- 注释该行:bind 127.0.0.1,表示可以让其他ip访问redis

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


———————————————数据库操作———————----——————

# 启动redis数据库服务端(当前文件下启动)
redis-server ./redis.windows.conf

# 启动redis客户端
redis-cli


# 向数据中添加调度器 队列名称
# 调度器的队列名称就是redis_key值
# 爬虫文件定义的redis_key = "sunQueue"   # 自定义队列名
lpush sunQueue  www.xxx.com   # 添加爬虫起始url

五、基于scrapy-redis分布式爬虫启动步骤

# 开启redis数据库
开启redis服务器:redis-server 配置文件
开启redis客户端:redis-cli

# 运行爬虫文件,监听起始请求对象
进入爬虫文件目录:cd ./spiders
运行爬虫文件:scrapy runspider SpiderFile

# 调度器队列中等待请求对象
向调度器队列中扔入一个起始url(在redis客户端中操作):lpush redis_key属性值  起始url

六、基于scrapy-redis分布式爬虫实例(东莞阳光网)

    需求:通过分布式爬虫(scrapy-redis)获取网站文章标题信息,url:http://wz.sun0769.com/index.php/question/questionType?type=4&page=

  爬虫文件:sun.py

# -*- coding: utf-8 -*-
import scrapy
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule
from fbssunPro.items import FbssunproItem

# 配置scrapy-redis分布式
# 给原生的scrapy提供了可以被共享的调度器和管道
from scrapy_redis.spiders import RedisCrawlSpider


# 继承分布式爬虫类(RedisCrawlSpider)
class SunSpider(RedisCrawlSpider):
    name = 'sun'
    # allowed_domains = ['www.xx.com']
    # 在分布式爬虫中,不再需要指定起始url
    # start_urls = ['http://www.xx.com/']

    # 指定被共享的调度器队列的名称
    redis_key = "sunQueue"

    # 规则解析器
    rules = (
        Rule(LinkExtractor(allow=r'type=4&page=\d+'), callback='parse_item', follow=True),
    )

    # 数据解析
    def parse_item(self, response):
        tr_list = response.xpath('//*[@id="morelist"]/div/table[2]//tr/td/table//tr')
        for tr in tr_list:
            # 获取所有的文章标题
            title = tr.xpath('./td[2]/a[2]/text()').extract_first()
            item = FbssunproItem()
            item['title'] = title

            # 提交数据到管道
            yield item

  Item对象类文件:items.py

import scrapy


class FbssunproItem(scrapy.Item):
    # define the fields for your item here like:
    title = scrapy.Field()

  管道文件类文件:pipelines.py

class FbssunproPipeline(object):
    # 持久化存储
    def process_item(self, item, spider):
        # item对象结果是一个字典
        print(item)
        return item

  爬虫配置文件:settings.py

BOT_NAME = 'fbssunPro'

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

# Obey robots.txt rules
ROBOTSTXT_OBEY = True

# 开启管道
ITEM_PIPELINES = {
   'fbssunPro.pipelines.FbssunproPipeline': 300,
}

# 配置调度器
DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"
SCHEDULER = "scrapy_redis.scheduler.Scheduler"
SCHEDULER_PERSIST = True

# 指定数据库
REDIS_HOST = '192.168.1.102'
REDIS_PORT = 6379

  完成!!!

 

posted @ 2019-08-11 19:12  WiseAdministrator  阅读(677)  评论(0编辑  收藏  举报