分布式爬虫
redis安装
- 用户自定义目录,也就是你想安装的位置,新建一个文件夹,注意你的路径里不要有中文
- 将redis-x64-3.2.100.zip压缩包 解压到你当前新建的文件夹里
- 将解压的文件的路径复制 并 配置到环境变量中
- 右击此电脑点击属性找到高级设置,然后点环境变量—系统变量—双击path—新建–粘贴路径即可
分布式
-
分布式爬虫
- 多台服务器机群,共同爬取数据
- 适用于数据量较大
- 提高了成本
-
原生scrapy 不能实现分布式,要通过scrapy-redis
- scrapy-redis提供了共享的调度器
- scrapy-redis提供了共享的管道
-
使用scrapy实现分布式的思路
- 为原生的scrapy框架提供共享的管道和调度器
- pip install scrapy-redis
-
配置及创建项目
-
创建工程
- scrapy startproject projectname
-
爬虫文件
- scrapy genspider -t crawl spidername www.baidu.com
-
修改爬虫文件
- 导包:from scrapy_redis.spiders import RedisCrawlSpider
- 将当前爬虫类的父类进行修改RedisCrawlSpider
- allowed_demains,start_urls 注释掉,添加一个新属性redis_key=“qn”(调度器队列的名称)
- 指定redis_key = ‘xxx’,即共享调度器队列名字
- lpush xxx url
- 数据解析:将解析的数据封装到item中然后向管道提交
-
配置文件的编写
-
指定管道
-
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
-
指定具体的redis
REDIS_HOST = 'redis服务器的ip地址' REDIS_PORT = 6379
-
修改redis配置并指定配置启动
-
启动程序:scrapy runspider xxx.py(需要进入spider文件夹)
-
向调度器队列中扔入一个起始的url(redis的客户端):lpush xxx www.xxx.com (xxx表示的就是redis_key的值)
-
-
代码演示
-
爬虫文件中
import scrapy from scrapy.linkextractors import LinkExtractor from scrapy.spiders import CrawlSpider, Rule from scrapy_redis.spiders import RedisCrawlSpider from fbsspider.items import FbsspiderItem class SunaskSpider(RedisCrawlSpider): # 爬虫名虽然运行时不再使用,但是不能删(******) name = 'sunask' # allowed_domains = ['baidu.com'] # start_urls = ['http://baidu.com/'] # 共享调度器 redis_key = 'sch' # http: // wz.sun0769.com / index.php / question / questionType?type = 4 & page = 30 link = LinkExtractor(allow=r'http://wz.sun0769.com.*?page=\d+') rules = ( Rule(link, callback='parse_item', follow=True), ) def parse_item(self, response): title_list = response.xpath('//a[@class="news14"]/@title').extract() for title in title_list: yield FbsspiderItem(title=title)
-
settings配置 就用上面笔记的复制粘贴就好了
"""
共享管道
"""
ITEM_PIPELINES = {
# 'fbsspider.pipelines.FbsspiderPipeline': 300,
'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
# 配置redis数据库
REDIS_HOST = '192.168.43.29'
REDIS_PORT = 6379
- scrapy runspider sunask.py 启动服务时需要注意一下操作,完成一下操作服务 才会执行 爬取流程
小插曲
- 框架开启多线程在settings中 打开这个即可
增量式爬虫
代码演示
- 爬虫文件中
import scrapy
from redis import Redis
from ..items import MovieItem
conn = Redis('localhost',6379)
class MvSpider(scrapy.Spider):
name = 'mv'
# allowed_domains = ['baidu.com']
start_urls = ['https://www.4567tv.tv/index.php?m=vod-list-id-5-pg-1-order--by-score-class--year--letter--area--lang-.html']
def parse(self, response):
link_list = response.xpath('//a[@class="stui-vodlist__thumb lazyload"]/@href').extract()
for link in link_list:
# sadd返回结果是1和0,1代表成功,0代表失败
ret = conn.sadd('link',link)
if ret == 1:
print('数据没爬过')
yield scrapy.Request(url='https://www.4567tv.tv'+link,callback=self.detail_parse)
else:
print('数据爬过了')
def detail_parse(self,response):
title = response.xpath('//h1[@class="title"]/text()').extract_first()
typ = response.xpath('//p[@class="data"][1]/a[1]/text()').extract_first()
localtion = response.xpath('//p[@class="data"][1]/a[2]/text()').extract_first()
pro = response.xpath('//span[@class="detail-sketch"]/text()').extract_first()
yield MovieItem(title=title,typ=typ,localtion=localtion,pro=pro)
- item文件中
import scrapy
class MovieItem(scrapy.Item):
# define the fields for your item here like:
title = scrapy.Field()
typ = scrapy.Field()
pro = scrapy.Field()
localtion = scrapy.Field()
- 管道中
import pymongo
class MoviePipeline(object):
conn = pymongo.MongoClient()
db = conn.movies
table = db.mv
def process_item(self, item, spider):
self.table.insert_one(dict(item))
return item
- settings中将管道打开,ua打开,robots协议改为false即可
基于数据指纹
-爬虫文件中
import scrapy
import hashlib
from redis import Redis
from ..items import JokesItem
conn = Redis('localhost',6379)
class JkSpider(scrapy.Spider):
name = 'jk'
# allowed_domains = ['baidu.com']
start_urls = ['http://xiaohua.zol.com.cn/lengxiaohua/']
def parse(self, response):
li_list = response.xpath('//ul[@class="article-list"]/li')
for li in li_list:
title = li.xpath('./span[2]/a/text()').extract_first()
content = ''.join(li.xpath('./div[2]//text()').extract())
# print('title:',title)
# print('content:',content)
data = title + content
fp = hashlib.md5(data.encode('utf-8')).hexdigest()
ret = conn.sadd('fp',fp)
if ret:
print('没爬过')
yield JokesItem(title=title,content=content)
else:
print('爬过了')
- 管道中
import pymongo
class JokesPipeline(object):
conn = pymongo.MongoClient()
db = conn.jjj
table = db.kkk
def process_item(self, item, spider):
self.table.insert_one(dict(item))
return item
- items中
import scrapy
class JokesItem(scrapy.Item):
# define the fields for your item here like:
title = scrapy.Field()
content = scrapy.Field()