基于python的scrapy爬虫,关于增量爬取是怎么处理的
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了基于python的scrapy爬虫,关于增量爬取是怎么处理的相关的知识,希望对你有一定的参考价值。
一、增量爬取的思路:即保存上一次状态,本次抓取时与上次比对,如果不在上次的状态中,便视为增量,保存下来。对于scrapy来说,上一次的状态是抓取的特征数据和上次爬取的 request队列(url列表),request队列可以通过request队列可以通过scrapy.core.scheduler的pending_requests成员得到,在爬虫启动时导入上次爬取的特征数据,并且用上次request队列的数据作为start url进行爬取,不在上一次状态中的数据便保存。二、选用BloomFilter原因:对爬虫爬取数据的保存有多种形式,可以是数据库,可以是磁盘文件等,不管是数据库,还是磁盘文件,进行扫描和存储都有很大的时间和空间上的开销,为了从时间和空间上提升性能,故选用BloomFilter作为上一次爬取数据的保存。保存的特征数据可以是数据的某几项,即监控这几项数据,一旦这几项数据有变化,便视为增量持久化下来,根据增量的规则可以对保存的状态数据进行约束。比如:可以选网页更新的时间,索引次数或是网页的实际内容,cookie的更新等 参考技术A
提供几个思路:
如果只是一次性的抓取某个网站的全部内容, 中途需要暂停并且恢复,只需要scrapy crawl somespider -s JOBDIR=crawls/somespider-1
如果需求是过滤某些url,但是网站的主入口不被过滤掉,比如典型的论坛类网站,你只想过滤掉帖子,但是却不想过滤掉板块,你可以定制一下requestSeen
如果使所有网站的动态过滤,比如是不是多了一个新回复,在url上的变化并不能体现出来,搜索引擎采用的是一系列的算法,判断某一个页面的更新时机。个人应用一般不会使用到(其实是自己也不懂,写出来提供一下思路,也许你会呢)。大部分的网页在进入下一级页面的时候都会有一个类似于最后更新时间,最后活动时间等等,可以根据这个来进行判断。
item['Url'] = response.url
然后在数据端把储存url的column设置成unique。
之后在python代码中捕获数据库commit时返回的异常,忽略掉或者转入log中都可以。
我使用的是SqlAlchemy。我是这么写的
from sqlalchemy.exc import IntegrityError
class XxxPipeline(object):
def process_item(self, item, spider):
#一些session.add()
#........
try:
session.commit()
print 'crawl %s done!' % item['Url']
except IntegrityError:
print 'skip %s .' % item['Url']
return item
虽然每次crawl都会重复抓取一些数据,但最终结果库内不会有相同的Url。
对于小规模的爬虫,这种重复抓取的成本基本可以忽略。
Scrapy框架--增量式爬虫
增量式爬虫
- 概念:监测网站数据更新的情况,只会爬取网站最新更新出来的数据。
- 分析:
- 指定一个起始url
- 基于CrawlSpider获取其他页码链接
- 基于Rule将其他页码链接进行请求
- 从每一个页码对应的页面源码中解析出每一个电影详情页的URL
- 核心:检测电影详情页的url之前有没有请求过,这里的示例使用了redis集合的去重特性,也可以使用python集合的去重特性。
- 将爬取过的电影详情页的url存储
- 存储到redis的set数据结构
- 对详情页的url发起请求,然后解析出电影的名称和简介
- 进行持久化存储
示例:爬取电影的名称和简介,只爬取之前没有爬取过的电影。
爬虫文件
# -*- coding: utf-8 -*- import scrapy from scrapy.linkextractors import LinkExtractor from scrapy.spiders import CrawlSpider, Rule from redis import Redis from moviePro.items import MovieproItem class MovieSpider(CrawlSpider): name = ‘movie‘ # allowed_domains = [‘www.xxx.com‘] start_urls = [‘https://www.4567kan.com/frim/index1.html‘] rules = ( Rule(LinkExtractor(allow=r‘index1-d+.html‘), callback=‘parse_item‘, follow=False), ) conn = Redis(host=‘127.0.0.1‘,port=6379) 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: title = li.xpath(‘./div/div/h4/a/text()‘).extract_first() detail_url = ‘https://www.4567kan.com/‘+li.xpath(‘./div/div/h4/a/@href‘).extract_first() ex = self.conn.sadd(‘urls‘, detail_url) # 利用redis的集合类型 如果存在 返回0 不存在 返回1 if ex == 1: print("爬取成功") yield scrapy.Request(url=detail_url,callback=self.parse_detail) else: print(‘暂无新资源‘) def parse_detail(self,response): item = MovieproItem() desc = response.xpath(‘/html/body/div[1]/div/div/div/div[2]/p[5]/span[2]/text()‘).extract_first() title = response.xpath(‘/html/body/div[1]/div/div/div/div[2]/h1/text()‘).extract_first() item[‘desc‘] = desc item[‘title‘] = title yield item def closed(self,response): self.conn.close()
items.py
import scrapy class MovieproItem(scrapy.Item): # define the fields for your item here like: # name = scrapy.Field() title = scrapy.Field() desc = scrapy.Field()
pipelines.py
import json class MovieproPipeline: def open_spider(self,spider): self.conn = spider.conn def process_item(self, item, spider): dic = { ‘title‘:item[‘title‘], ‘desc‘: item[‘desc‘] } dic = json.dumps(dic) # 向redis中存放一个数据结构 self.conn.lpush(‘movieDate‘,dic) return item
以上是关于基于python的scrapy爬虫,关于增量爬取是怎么处理的的主要内容,如果未能解决你的问题,请参考以下文章
基于python的scrapy爬虫,关于增量爬取是怎么处理的
爬虫07 /scrapy图片爬取中间件selenium在scrapy中的应用CrawlSpider分布式增量式