scrapy入门(四)分布式和增量式
一. 分布式
-
概念 : 需要搭建一个分布式的机群, 然后在机群的每一台电脑中执行同一组程序, 让其对某一个网站的数据进行联合分布爬取
-
scrapy + scrapy_redis实现分布式
scrapy_redis组件的功能 :
- 提供可被共享的调度器和管道
- 数据只能存储到redis数据库中
-
实现流程
- 修改源文件
#以创建CrawlSpider为例 #导包 from scrapy_redis.spiders import RedisCrawlSpider #修改爬虫类的父类 class FbsSpider(RedisCrawlSpider): #注释掉allow_domains和start_urls,分布式不推荐使用start_urls #添加新属性 redis_key ='fbsQueue'#表示的是可以被共享的调度器队列的名称,将起始url直接放到调度器中
- settings文件的配置
ITEM_PIPELINES = { 'scrapy_redis.pipelines.RedisPipeline':300 } #确保所有的爬虫通过Redis去重 DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter" #启用Redis调度存储请求队列 SCHEDULER = "scrapy_redis.scheduler.Scheduler" #不清除Redis队列,起到记忆功能 #例如隔几天后重新爬取同一个网站,设置为True则之前爬取过的数据不再爬取 SCHEDULER_PERSIST = True #指定redis数据库 #指定连接到redis时使用的端口和地址(可选) REDIS_HOST = '指定一个ip地址' REDIS_PORT = 6379
-
对redis数据库的配置文件进行操作(redis.windows.conf)
- 关闭默认绑定 : 56 Line : #bind 127.0.0.1
- 关闭保护模式 :75 Line : protect-mode no\
-
携带配置文件启动redis服务端, 再启动客户端
- redis-server.exe redis.windows.conf
- redis-cli
-
在pycharm中启动程序
scrapy run spider fbs.py #fbs是自定义爬虫名之后程序会等待我们进行redis数据库的操作, 才会继续进行
-
向调度器的队列中扔入一个起始的url :
启动redis客户端,输入lpush fbsQueue "起始url"
二. 增量式
核心机制: 对详情页的url去重. redis的set实现去重
原理实现过程:
- 需要两张表, 一张保存数据源文件, 一份保存数据文件生成的数据指纹
- 每次先将爬取到的文件生成一份对应的数据指纹,
- 如果已经存在数据指纹库中, 则不需要向管道提交,
- 否则保存数据指纹和原文件
#python源文件 from redis import Redis class ZlsSpider(CrawlSpider): #将连接对象作为ZlsSpider类的一个属性 conn = Redis(host = '127.0.0.1',port = 6379) pass def parse_item(self,response): #... detail_url = li.xpath('xxxxxxx') #将解析得到的url和redis数据库中的表作比较 #对于不需要深度爬取的页面,可以将要爬取的数据文件拼成一个字符串,然后放入到hashlib中生成一个专属source_id,就相当于url,以后爬取的时候同样判断这个source_id是否在对应的data_id表中 #source = item['author'] + item['content'] #source_id =hashlib.sha256(source.encode()).hexdigest() #ex = self.conn.sadd('data_id',source_id) #sadd()功能:如果url存在则不向表中添加数据并返回0,不存在则向表中添加并返回1 ex = self.conn.sadd('urls_id',detail_url)#urls_id为数据库记录url是否爬取过的表 if ex == 1 : #手动发送请求 yield scrapy.Request(detail_url,callback=self.parse_detail,meta={'item':item}) def parse_detail(self,response): content = response.xpath('xxxxxxxxxx').extract_first() item = response.meta['item'] #item对象在前面的for循环中创建,保证每次循环请求不同的url时生成一个item对象 item['content'] =content #将item对象传递给管道 yield item
#pipelines文件中 def process_item(self, item, spider): #接受爬虫类的conn conn = spider.conn conn.lpush('detail_data',item) #detail_data用来保存爬取的数据信息 return item
三. 反爬机制总结
- robots
- UA伪装
- 验证码
- 代理
- cookie
- 动态变化的请求参数
- js加密
- js混淆
- 图片懒加载
- 动态数据的捕获
- selenium :规避检测