分布式
需要搭建一个分布式的机群,在机群的每一台电脑中执行同一组程序,让其对某一个网站的数据进行联合分布爬取。
-
原生的scrapy不能实现分布式的原因
- 因为调度器不可以被共享
- 管道不可以被共享
-
如何实现分布式
- scrapy+scrapy_redis实现分布式
-
scrapy_redis组件作用
- 可以提供可被共享的调度器和管道
- 特性:数据只可以存储到redis数据库
-
分布式的实现流程
- pip instal scrapy-redis
- 创建工程
- cd到工程目录
- 创建爬虫文件(a.创建基于Spider的爬虫文件 b.创建CrawlSpider的爬虫文件)
- 修改爬虫类
- 倒包:from scrapy_redis.spiders import RedisCrawlSpider(根据创建类型选择)
- 修改当前爬虫类的父类为 RedisCrawlSpider
- allowed_domains和start_urls删除
- 添加一个新属性:redis_key = ‘fbsQueue’ 表示可以被共享的调度器队列的名称
- 编写爬虫类的其他操作(常规操作)
- settings配置文件的配置
-
UA伪装
-
Robots
-
管道的指定:ITEM_PIPELINES = {‘scrpay_redis.pipelines.RedisPipeline’: 400}
-
指定调度器:
- DUPEFILTER_CLASS = “scrapy_redis.dupefilter.RFPDupeFilter” 使用scrapy-redis组件的去重队列
- SCHEDULER = “scrapy_redis.scheduler.Scheduler” 使用scrapy-redis组件自己的调度区
- SCHEDULER_PERSIST = True 增量式使用,也就是当爬虫结束,要不要清楚redis中请求队列和去重,True为不清除,持久化存储
-
指定redis数据库
- REDIS_HOST = ‘redis服务的ip地址’
- REDIS_PORT = 6379
- REDIS_ENCODING = ‘utf-8’
-
redis的配置文件进行配置redis.windows.conf:
- 关闭默认绑定:56行 #bind 127.0.0.1
- 关闭保护模式:75行 protected-mode no
-
启动redis服务端和客户端
- redis-server.ext redis.windows.conf
- redis-cli
-
启动程序
- scrapy runspider xxx.py
-
向调度器的队列中扔入一个起始的url
- 队列是存在于redis中
- 开启redis的客户端:lpush fbsQueue http://wz.sun0769.com/political/index/politicsNewest?id=1&page=
-
增量式
用于检测网站数据更新的情况。核心机制:去重。redis的set实现去重
爬取4567电影名称和电影详情——深度爬取
import scrapy
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule
from redis import Redis
from movie_zls.items import MovieZlsItem
class MovieSpider(CrawlSpider):
conn = Redis(host='127.0.0.1', port=6379)
name = 'movie'
# allowed_domains = ['www.xxx.com']
start_urls = ['https://www.4567kan.com/frim/index6.html']
rules = (
Rule(LinkExtractor(allow=r'frim/index6-\d.html'), callback='parse_item', follow=True),
)
def parse_item(self, response):
li_list = response.xpath('/html/body/div[1]/div/div/div/div[2]/ul/li')
for li in li_list:
name = li.xpath('./div/a/@title').extract_first()
item = MovieZlsItem()
item['name'] = name
detail_url = 'https://www.4567kan.com' + li.xpath('./div/a/@href').extract_first()
# 记录爬过的电影详情页的url。ex=0插入失败,ex=1插入成功
ex = self.conn.sadd('movie_detail_urls', detail_url)
if ex == 1:
print('捕获到新数据')
yield scrapy.Request(detail_url, callback=self.parse_detail, meta={'item': item})
else:
print('无数据更新')
def parse_detail(self, response):
desc = response.xpath('/html/body/div[1]/div/div/div/div[2]/p[5]/span[2]/text()').extract_first()
item = response['item']
item['desc'] = desc
yield desc
class MovieZlsPipeline:
def process_item(self, item, spider):
conn = spider.conn
conn.lpush('movieData', item)
return item
糗事百科爬取文章内容和标题——不用深度爬取
爬取标题和文章,都在同一个页面中就可爬取到,添加数据指纹
#将解析到的数据值生成一个唯一的标识进行redis存储
source = item['author']+item['content']
source_id = hashlib.sha256(source.encode()).hexdigest()
#将解析内容的唯一表示存储到redis的data_id中
ex = self.conn.sadd('data_id',source_id)
if ex == 1:
print('该条数据没有爬取过,可以爬取......')
yield item
else:
print('该条数据已经爬取过了,不需要再次爬取了!!!')
版权声明:本文为qq_30307045原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。