一、爬虫分布式原理:
scrapy-redis实现分布式,其实从原理上来说很简单,这里为描述方便,我们把自己的核心服务器称为master,而把用于跑爬虫程序的机器称为slave
我们知道,采用scrapy框架抓取网页,我们需要首先给定它一些start_urls,爬虫首先访问start_urls里面的url,再根据我们的具体逻辑,对里面的元素、或者是其他的二级、三级页面进行抓取。而要实现分布式,我们只需要在这个starts_urls里面做文章就行了
我们在master上搭建一个redis数据库`(注意这个数据库只用作url的存储),并对每一个需要爬取的网站类型,都开辟一个单独的列表字段。通过设置slave上scrapy-redis获取url的地址为master地址。这样的结果就是,尽管有多个slave,然而大家获取url的地方只有一个,那就是服务器master上的redis数据库
并且,由于scrapy-redis自身的队列机制,slave获取的链接不会相互冲突。这样各个slave在完成抓取任务之后,再把获取的结果汇总到服务器上
好处
程序移植性强,处理好路径问题,把slave上的程序移植到另一台机器上运行,基本上就是复制粘贴
0、分布式爬虫的实现:
- 使用三台机器,一台是win10,两台是centos,分别在两台机器上部署scrapy来进行分布式抓取一个网站
- win10的ip地址,用来作为redis的master端,centos的机器作为slave
- master的爬虫运行时会把提取到的url封装成request放到redis中的数据库:“dmoz:requests”,并且从该数据库中提取request后下载网页,再把网页的内容存放到redis的另一个数据库中“dmoz:items”
- slave从master的redis中取出待抓取的request,下载完网页之后就把网页的内容发送回master的redis
- 重复上面的3和4,直到master的redis中的“dmoz:requests”数据库为空,再把master的redis中的“dmoz:items”数据库写入到mongodb中
- master里的reids还有一个数据“dmoz:dupefilter”是用来存储抓取过的url的指纹(使用哈希函数将url运算后的结果),是防止重复抓取的
master节点环境搭配:
redis 的配置 参考:window 中redis 的配置和开启_宠乖仪的博客-
slave 节点环境配置:
1、搭建python环境
参考:linux 安装python 坏境_宠乖仪的博客
2、安装scrapy
pip install scrapy
二、scrapy-redis框架的安装
scrapy-redis参考:GitHub - rmax/scrapy-redis: Redis-based components for Scrapy.
pip install scrapy-redis
1、方法一
settings.py
# 指纹 作用:redis数据库中url去重类
DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"
# 调度器 启用Redis调度存储请求队列
SCHEDULER = "scrapy_redis.scheduler.Scheduler"
# 不清除Redis队列、这样可以暂停/恢复 继续 爬取
SCHEDULER_PERSIST = True
ITEM_PIPELINES = {
# 把数据 放在redis里面
'scrapy_redis.pipelines.RedisPipeline': 300
}
REDIS_HOST = 'localhost' #master IP
REDIS_PORT = 6379
2、方法二
spider.py
from scrapy_redis.spiders import RedisSpider
import scrapy
class LianjiaSpider(RedisSpider):
name = 'lianjia'
allowed_domains = ['lianjia.com']
page = 2
# start_urls = ['https://sh.lianjia.com/ershoufang/pg1/']
# myscrawl 自己随便定义
redis_key ='myscrawl:start_urls'
# # 优先获取列表
# def start_requests(self):
# for i in range(1,101):
# yield scrapy.Request('https://sh.lianjia.com/ershoufang/pg{i}/')
def parse(self, response):
url_list=response.xpath('//div[@class="info clear"]/div[@class="title"]/a/@href').getall()
for url in url_list:
yield scrapy.Request(url,callback=self.parse_info)
if self.page <101:
yield scrapy.Request(f'https://sh.lianjia.com/ershoufang/pg{self.page}/')
def parse_info(self, response):
title = response.xpath('//div[@class="communityName"]/a[1]/text()').get()
action = response.xpath('string(//div[@class="areaName"]/span[@class="info"])').get()
momey = response.xpath('//div[@class="price"]/span').get()
yield {
'title':title,
'action':action,
'momey':momey
}
3、方法三
scrapy genspider -t crawl name allow_domains
spider.py
import scrapy
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule
from scrapy_redis.spiders import RedisCrawlSpider
class XsSpider(RedisCrawlSpider):
name = 'xs'
allowed_domains = ['biquge5200.net']
start_urls = ['http://www.biquge5200.net/0_111/75039.html']
rules = (
Rule(LinkExtractor(restrict_xpaths=r'//div[@class="bottem1"]/a[4]'), callback='parse_item', follow=True),
)
def parse_item(self, response):
title= response.xpath('//div[@class="bookname"]/h1/text()').get()
content = response.xpath('string(//div[@id="content"])').get()
yield {
'title':title,
'content':content
}
4、方式二和方法三程序运行
scrapy crawl name
# 这个命令是在redis-cli中运行
# redis_key 是 spider.py文件中的redis_key的值
# url 开始爬取地址,不加双引号
lpush (redis_key) url #括号不用写
5、redis的数据导给monogo
数据库与数据库之间的交互_宠乖仪的博客