
上QQ阅读APP看书,第一时间看更新
2.4.3 增量爬虫技术
某些网站会定时在原有网页数据的基础上更新一批数据。例如某电影网站会实时更新一批最近热门的电影,小说网站会根据作者创作的进度实时更新最新的章节数据等。在遇到类似的场景时,我们便可以采用增量式爬虫。增量爬虫技术(incremental Web crawler)就是通过爬虫程序监测某网站数据更新的情况,以便可以爬取到该网站更新后的新数据。
关于如何进行增量式的爬取工作,以下给出三种检测重复数据的思路:1)在发送请求之前判断这个URL是否曾爬取过;2)在解析内容后判断这部分内容是否曾爬取过;3)写入存储介质时判断内容是否已存在于介质中。第一种思路适合不断有新页面出现的网站,比如小说的新章节、每天的实时新闻等;第二种思路则适合页面内容会定时更新的网站;第三种思路则相当于最后一道防线。这样做可以最大限度地达到去重的目的。
不难发现,实现增量爬取的核心是去重。目前存在两种去重方法。第一,对爬取过程中产生的URL进行存储,存储在Redis的set中。当下次进行数据爬取时,首先在存储URL的set中对即将发起的请求所对应的URL进行判断,如果存在则不进行请求,否则才进行请求。第二,对爬取到的网页内容进行唯一标识的制定(数据指纹),然后将该唯一标识存储至Redis的set中。当下次爬取到网页数据的时候,在进行持久化存储之前,可以先判断该数据的唯一标识在Redis的set中是否存在,从而决定是否进行持久化存储。
关于增量爬虫的使用方法示例如下所示。
【例2-3】爬取4567tv网站中所有的电影详情数据
import scrapy from scrapy.linkextractors import LinkExtractor from scrapy.spiders import CrawlSpider, Rule from redis import Redis from incrementPro.items import IncrementproItem class MovieSpider(CrawlSpider): name = 'movie' # allowed_domains = ['www.xxx.com'] start_urls = ['http://www.4567tv.tv/frim/index7-11.html'] rules = ( Rule(LinkExtractor(allow=r'/frim/index7-\d+\.html'), callback='parse_item', follow=True), ) # 创建Redis链接对象 conn = Redis(host='127.0.0.1', port=6379) def parse_item(self, response): li_list = response.xpath('//li[@class="p1 m1"]') for li in li_list: # 获取详情页的url detail_url = 'http://www.4567tv.tv' + li.xpath('./a/@href').extract_first() # 将详情页的url存入Redis的set中 ex = self.conn.sadd('urls', detail_url) if ex == 1: print('该url没有被爬取过,可以进行数据的爬取') yield scrapy.Request(url=detail_url, callback=self.parst_detail) else: print('数据还没有更新,暂无新数据可爬取!') # 解析详情页中的电影名称和类型,进行持久化存储 def parst_detail(self, response): item = IncrementproItem() item['name'] = response.xpath('//dt[@class="name"]/text()').extract_first() item['kind'] = response.xpath('//div[@class="ct-c"]/dl/dt[4]//text()').extract() item['kind'] = ''.join(item['kind']) yield it
管道文件:
from redis import Redis class IncrementproPipeline(object): conn = None def open_spider(self,spider): self.conn = Redis(host='127.0.0.1',port=6379) def process_item(self, item, spider): dic = { 'name':item['name'], 'kind':item['kind'] } print(dic) self.conn.push('movieData',dic) # 如果push不进去,那么dic变成str(dic)或者改变redis版本 pip install -U redis==2.10.6 return item