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()