Source code for sspider.spider

# -*- coding = utf-8 -*-
# author:pengr

'''
sspider.抽象结构
~~~~~~~~~~~~

该模块时爬虫整体的抽象架构,可直接继承该模块中的类进行扩展功能
'''

from .utils import typeassert, get__function_name


[docs]class AbstractDownloader(object): ''' 下载器 对传入的请求进行请求下载 '''
[docs] def download(self, request): ''' 对request进行请求下载,需要将请求到的response返回 @param :: request : 请求对象 return response ''' raise NotImplementedError("未实现的父类方法: %s.%s" % ( self.__class__.__name__, get__function_name()))
[docs]class AbstractParser(object): ''' 解析器 对传入的文本进行解析 '''
[docs] def parse(self, response): ''' 对response进行解析,需要将解析到的requests与data返回 @param :: response : 响应对象 return requests,data ''' raise NotImplementedError("未实现的父类方法: %s.%s" % ( self.__class__.__name__, get__function_name()))
[docs]class AbstractRequestManager(object): ''' 请求管理器 管理所有的请求 '''
[docs] def add_new_requests(self, requests): ''' 模板方法,不需要子类重写 添加requests序列到requestManager中进行管理 @param :: requests : request对象列表 return None ''' for request in requests: self.add_new_request(request)
[docs] def add_new_request(self, request): ''' 添加request对象到requestManager中进行管理 @param :: request : request对象 return None ''' raise NotImplementedError("未实现的父类方法: %s.%s" % ( self.__class__.__name__, get__function_name()))
[docs] def has_new_request(self): ''' 判断requestManager中是否还有新的请求,返回布尔类型结果 return Bool ''' raise NotImplementedError("未实现的父类方法: %s.%s" % ( self.__class__.__name__, get__function_name()))
[docs] def get_new_request(self): ''' 从requestManager中取新的请求 return request ''' raise NotImplementedError("未实现的父类方法: %s.%s" % ( self.__class__.__name__, get__function_name()))
[docs]class AbstractWritter(object): ''' 数据写入类 将数据以特定格式写入到磁盘中 '''
[docs] def write(self, data): ''' 将数据data写入磁盘 return None ''' raise NotImplementedError("未实现的父类方法: %s.%s" % ( self.__class__.__name__, get__function_name()))
[docs] def write_buffer(self, item): ''' 缓存数据 return None ''' raise NotImplementedError("未实现的父类方法: %s.%s" % ( self.__class__.__name__, get__function_name()))
[docs] def flush_buffer(self): ''' 刷新缓存数据到磁盘上 return None ''' raise NotImplementedError("未实现的父类方法: %s.%s" % ( self.__class__.__name__, get__function_name()))
[docs]class AbstractLogger(object): ''' 日志类 记录爬虫运行 '''
[docs] def debug(self, message): ''' debug级别日志 ''' raise NotImplementedError("未实现的父类方法: %s.%s" % ( self.__class__.__name__, get__function_name()))
[docs] def info(self, message): ''' info级别日志 ''' raise NotImplementedError("未实现的父类方法: %s.%s" % ( self.__class__.__name__, get__function_name()))
[docs] def warn(self, message): ''' warn级别日志 ''' raise NotImplementedError("未实现的父类方法: %s.%s" % ( self.__class__.__name__, get__function_name()))
[docs] def exception(self, message): ''' exception级别日志 ''' raise NotImplementedError("未实现的父类方法: %s.%s" % ( self.__class__.__name__, get__function_name()))
[docs] def error(self, message): ''' error级别日志 ''' raise NotImplementedError("未实现的父类方法: %s.%s" % ( self.__class__.__name__, get__function_name()))
[docs]class AbstractSpider(object): ''' 爬取调度器 @member :: downloader : 下载器 @member :: parser : 解析器 @member :: requestManager : 请求管理器 @member :: writter : 文本写入 @member :: logger : 日志 ''' attrs = [ 'downloader', 'parser', 'requestManager', 'writter', 'logger' ] @typeassert(downloader=AbstractDownloader, parser=AbstractParser, requestManager=AbstractRequestManager, writter=AbstractWritter, logger=AbstractLogger) def __init__(self, downloader=AbstractDownloader(), parser=AbstractParser(), requestManager=AbstractRequestManager(), writter=AbstractWritter(), logger=AbstractLogger()): self.downloader = downloader self.parser = parser self.requestManager = requestManager self.writter = writter self.logger = logger def __call__(self, request): self.run(request)
[docs] def run(self, request=None, requests=[]): ''' 运行爬虫方法,从requestManager中取出可用的request,然后扔进下载器中进行下载,通过解析器对下载到的文档进行解析; 需要传入一个或者一组request作为初始request进行抓取 @param :: request : 请求 return : None ''' self.__start_icon() self.logger.info('\tStart crawl...') if request: self.requestManager.add_new_request(request) if requests: self.requestManager.add_new_request(requests) while self.requestManager.has_new_request(): request = self.requestManager.get_new_request() self.crawl(request) self.logger.info('\tEnd crawl...')
[docs] def crawl(self, request): ''' 对request进行请求进行爬取并解析结果的运行单元,子类可对该方法重写进行多线程、多进程运行或异步抓取与解析 下载器对传入的request进行下载,解析器解析下载到的文档,并将解析出的request扔进requestManager中进行管理,以进行深度爬取;将解析出的data扔进writter中,将数据存储到磁盘上 @param :: request : 请求 return None ''' try: self.logger.info('\t'+request.url) response = self.downloader.download(request) if response.status_code == 200: requests, data = self.parser.parse(response) self.requestManager.add_new_requests(requests) self.writter.write_buffer(data) else: self.logger.warn( 'crawled data is None and response_status is ' + str(response.status_code)) except Exception as e: self.logger.exception('\tCrawling occurs error\n' + e.__repr__())
[docs] def write(self): ''' 传入文件名及格式,数据写入文件 ''' self.writter.write_buffer_flush()
def __start_icon(self): icon = ''' _ _ ___ _ _ ___<_>._ _ _ ___ | | ___ / __> ___ <_> _| | ___ _ _ <_-<| || ' ' || . \| |/ ._>\__ \| . \| |/ . |/ ._>| '_> /__/|_||_|_|_|| _/|_|\___.<___/| _/|_|\___|\___.|_| |_| |_| ''' print(icon) print()