- 概念:我们需要搭建一个分布式的机群,让其对一组资源进行分布联合爬取
- 作用:提升爬取数据的效率
- 如何实现分布式?
- 安装一个scrapy-redis的组件(使用的是redis数据库)
- 原生的scrapy是不可以实现分布式爬虫的,必须让scrapy结合着scrapy-redis组件一起实现分布式爬虫
- 为什么原生的scrapy框架不能实现分布式爬虫 ?
- 1.调度器不可以被分布式机群共享
2.管道不可以被分布式机群共享
- 1.调度器不可以被分布式机群共享
- scrapy-redis组件作用:
- 可以给原生的scrapy框架提供可以共享的调度器和管道
- 实现流程:
- 创建一个工程
- 创建基于CrawlSpider的爬虫文件
- 修改当前的爬虫文件:
- 导包:from scrapy_redis.spiders import RedisCrawlSpider
- 将start_urls和allowed_domins进行注释
- 添加一个新属性:redis_key = ‘sun’ 即可以被共享的调度器队列的名称
- 编写数据解析相关操作
- 将当前爬虫类的父类修改成RedisCrawlSpider
- 修改配置文件settings
- 指定使用可以被共享的管道(死的,可以直接复制)
ITEM_PIPELINES = {
‘scrapy_redis.pipelines.RedisPipeline’: 400,
} - 指定可以共享的调度器(死的,可以直接复制)
#增加了一个去重容器类的配置,作用 使用Redis的set集合来存储请求的指纹数据,
从而实现请求去重的持久化
DUPEFILTER_CLASS =“scrapy_redis.dupefilter.RFPDupeFilter”
#使用scrapy_redis组件自己的调度器
SCHEDULER = “scrapy_redis.scheduler.Scheduler”
#配置调度器是否要持久化,也就是当爬虫结束了,要不要清空Redis中请求队列和去重指纹的
set。如果是True,不清空,即只爬取没有爬到的数据,爬过的就不爬了
SCHEDULER_PERSIST=True - 指定resid服务器:
REDIS_HOST=‘redis远程服务器的IP(自行修改)’
REDIS_PORT=‘端口号’
- 指定使用可以被共享的管道(死的,可以直接复制)
- redis相关操作设置:(安装可参考菜鸟教程)
- 配置redis的配置文件:
- Linux或者mac:redis.conf
- Windows:redis.windows.conf
- 打开配置文件修改(vi redis.windows.conf)(Windows直接记事本修改):
- 将 bind 127.0.0.1删除
- 关闭保护模式:protected-mode yes改为no
- 结合着配置文件开启redis服务
- redis_server 配置文件(redis.windows.conf)
- 启动客户端
- redis_cli.exe
- 执行工程(进入到spiders目录下)
- scrapy runspider xxx.py
- 向调度器的队列中放入一个起始url:
- 调度器的队列在redis客户端中
- lpush xxx(队列名称) www.xxx.com
- 调度器的队列在redis客户端中
- 爬取到的数据存储在了redis的proName:items这个数据结构中
- 配置redis的配置文件:
其实分布式的代码并不难,主要是配置比较费时,下面代码参考前一篇博客。
import scrapy
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule
from scrapy_redis.spiders import RedisCrawlSpider
from fenbushipro.items import FenbushiproItem
class FbsSpider(RedisCrawlSpider):
name = 'fbs'
# allowed_domains = ['www.xxx.com']
# start_urls = ['http://www.xxx.com/']
redis_key = 'sun'
rules = (
Rule(LinkExtractor(allow=r'id=1&page=\d+'), callback='parse_item', follow=True),
)
def parse_item(self, response):
li_list = response.xpath('/html/body/div[2]/div[3]/ul[2]/li')
for li in li_list:
new_num = li.xpath('/html/body/div[2]/div[3]/ul[2]/li[1]/span[1]/text()').extract_first()
new_title = li.xpath('/html/body/div[2]/div[3]/ul[2]/li[1]/span[3]/a/text()').extract_first()
print(new_num,new_title) #用于测试程序是否出错
item = FenbushiproItem()
item['new_num'] = new_num
item['new_title'] = new_title
yield item
ITEM_PIPELINES = {
'scrapy_redis.pipelines.RedisPipeline': 300,
}
#指定可以共享的调度器
#增加了一个去重容器类的配置,作用 使用Redis的set集合来存储请求的指纹数据,
#从而实现请求去重的持久化
DUPEFILTER_CLASS ="scrapy_redis.dupefilter.RFPDupeFilter"
#使用scrapy_redis组件自己的调度器
SCHEDULER = "scrapy_redis.scheduler.Scheduler"
#配置调度器是否要持久化,也就是当爬虫结束了,要不要清空Redis中请求队列和去重指纹的
#set。如果是True,不清空
SCHEDULER_PERSIST=True
#指定服务器
REDIS_HOST = '127.0.0.1'
REDIS_PORT = 6379