TinScrapy-简化的Scrapy原码-查看爬虫的执行流程
学习了自定义的TinyScrapy框架,整理出以下定注释的代码
from twisted.web.client import getPage,defer
from twisted.internet import reactor
import queue class Response(object):
'''
对返回内容进行封装为UTF8格式
'''
def __init__(self,body,request):
self.body=body
self.request=request
self.url=request.url @property
def text(self):
return self.body.decode('utf-8') class Request(object):
'''
封装,请求的URL 与回调函数
'''
def __init__(self,url,callback):
self.url=url
self.callback=callback class Scheduler(object):#调度器
'''
任务调度器
'''
def __init__(self,engine):
self.q=queue.Queue()#队列
self.engine=engine
def enqueue_request(self,request):
self.q.put(request)#加入队列
def next_request(self):
try:
req=self.q.get(block=False)#从队列中取出
except Exception as e:
req=None
return req
def size(self):
return self.q.qsize()#队列是的个数 class ExecutionEngine(object): #爬虫引擎 def __init__(self):#构造
self._closewait=None #关闭引擎调用 默认为不关闭
self.running=True#引擎默认为运行状态
self.start_requests=None #开始爬取任务
self.scheduler=Scheduler(self)#调度器 类 构造自己放入调度器,传回自身
self.inprogress =set() #集合 并发数 def check_empty(self,response):#检测任务是否为空
if not self.running:
print('任务终止。。。。')
self._closewait.callback(None) def _next_request(self):#下一个爬取任务
while self.start_requests:#存在爬取任务
try:
request=next(self.start_requests)
except StopIteration:#如果执行出错
self.start_requests=None#任务变为空
else:
self.scheduler.enqueue_request(request)#放入调度器中
print(len(self.inprogress),'=>总任务数',self.scheduler.size(),'=>调度器中的任务数')
while len(self.inprogress)< 5 and self.scheduler.size()>0: #最大并发数为 5
request=self.scheduler.next_request()#调度器中任务 调用自身
if not request:
break
self.inprogress.add(request)#加入任务并发
d=getPage(bytes(request.url,encoding='utf-8'))#开始爬取任务
#d.addError=()#任务出错时执行
#d.addCallback=()#任务成功完成时执行
d.addBoth(self._handle_downloader_output,request)#下载 任务 #无论是否成功都执行 有返回值 运行_handle
d.addBoth(lambda x,req:self.inprogress.remove(req),request)#正在运行的进行移除
d.addBoth(lambda x:self._next_request())#执行本身的函数
if len(self.inprogress)==0 and self.scheduler.size()==0:
self._closewait.callback(None)#执行关闭程序 def _handle_downloader_output(self,body,request):#任务后的回调函数
'''
获取内容,执行回调函数,并且把回调函数中的返回值获取,并添加到队列中
:param response:
:param request:
:return:
'''
import types
response=Response(body,request)#进行封装
func=request.callback or self.spider.parse#如果有回返值,func取回返值 否则 等于任务的最开始内容
gen=func(response)
if isinstance(gen,types.GeneratorType):#是否是生成器对象
for req in gen:
self.scheduler.enqueue_request(req) @defer.inlineCallbacks
def start(self):
self._closewait=defer.Deferred()#生成一个空任务对象 用于保持程序
yield self._closewait @defer.inlineCallbacks
def open_spider(self,spider,start_requests):#传入封装好的Requset ,任务迭代器
self.start_requests=start_requests#任务迭代器
self.spider=spider#封装好的Requset (请求的URL 与回调函数)
yield None #生成器,断点缓存
reactor.callLater(0,self._next_request)#立刻执行 下一个爬取任务 class Crawler(object):#爬虫执行类
def __init__(self,spidercls):#传入任务(ChoutiSpider,等)
self.spidercls=spidercls
self.spider =None
self.engine=None @defer.inlineCallbacks
def crawl(self):
self.engine=ExecutionEngine()#类实例化 引擎
self.spider=self.spidercls()#实例化任务
start_requests =iter(self.spider.start_requests())#迭代器
yield self.engine.open_spider(self.spider,start_requests)#引擎启动
yield self.engine.start()#开始执行 class CrawlerProcess(object):#爬虫任务器 类
def __init__(self):
self._active=set()#已经执行任务集合
self.crawlers=set()# 爬虫任务集合 def crawl(self,spidercls,*args,**kwargs):#传入爬虫任务
crawler=Crawler(spidercls)#爬虫任务开始 实例化
self.crawlers.add(crawler)#爬虫任务集合
d=crawler.crawl(*args,**kwargs)#爬取任务实例化 运行
self._active.add(d)#加入已经执行任务集合
return d def start(self):
d1=defer.DeferredList(self._active)#实例化执行对象
d1.addBoth(self._stop_reactor)#所有任务结束 调用 stop方法
reactor.run() def _stop_reactor(self,_=None):#任务停止
reactor.stop() class Spider(object):
def start_requests(self):
for url in self.start_urls:
yield Request(url,self.parse)#生成器,对URL与回调函数进行封装 #=========具体爬虫任务=======start==========#
class ChoutiSpider(Spider):#
name='chouti'
start_urls=['http://dig.chouti.com/',]
def parse(self,response):
print(response.text) class CnblogsSpider(Spider):
name='cnblogs'
start_urls=['http://www.cnblogs.com/',]
def parse(self,response):
print(response.text)
#=========具体爬虫任务=======end==========# if __name__=='__main__':
spider_cls_list=[ChoutiSpider,CnblogsSpider]#加入任务列表
crawler_process=CrawlerProcess()#实例化爬虫任务器
for spider_cls in spider_cls_list:
crawler_process.crawl(spider_cls)#传入任务
crawler_process.start()#开始执行
TinyScrapy
TinScrapy-简化的Scrapy原码-查看爬虫的执行流程的更多相关文章
- Yii2 源码分析 入口文件执行流程
Yii2 源码分析 入口文件执行流程 1. 入口文件:web/index.php,第12行.(new yii\web\Application($config)->run()) 入口文件主要做4 ...
- asyncio源码分析之基本执行流程
基于async关键字的原生协程 # 定义一个简单的原生协程cor async def cor(): print('enter cor') print('exit cor') print(type(co ...
- 【推理引擎】从源码看ONNXRuntime的执行流程
目录 前言 准备工作 构造 InferenceSession 对象 & 初始化 让模型 Run 总结 前言 在上一篇博客中:[推理引擎]ONNXRuntime 的架构设计,主要从文档上对ONN ...
- 浩哥解析MyBatis源码(一)——执行流程
原创作品,可以转载,但是请标注出处地址: 一.MyBatis简介 MyBatis框架是一种轻量级的ORM框架,当下十分流行,配合Spring+Spring MVC组成SSM框架,能够胜任几乎所有的项目 ...
- Mybatis 系列10-结合源码解析mybatis 的执行流程
[Mybatis 系列10-结合源码解析mybatis 执行流程] [Mybatis 系列9-强大的动态sql 语句] [Mybatis 系列8-结合源码解析select.resultMap的用法] ...
- scrapy 6023 telnet查看爬虫引擎相关状态
Telnet终端(Telnet Console) Scrapy提供了内置的telnet终端,以供检查,控制Scrapy运行的进程. telnet仅仅是一个运行在Scrapy进程中的普通python终端 ...
- Flask源码解析:Flask应用执行流程及原理
WSGI WSGI:全称是Web Server Gateway Interface,WSGI不是服务器,python模块,框架,API或者任何软件,只是一种规范,描述服务器端如何与web应用程序通信的 ...
- 通过更改scrapy源码进行spider分发实现一个综合爬虫
最近我正写一个项目,项目的需求如下一,要爬取大约100种几百个网页的类容,并且这些网页的爬取频率不一样,有些一天爬取一次,有些一周爬取一次,二,网页爬取内容有变化,也就是说要爬取的内容会根据需求进行改 ...
- 基于Python,scrapy,redis的分布式爬虫实现框架
原文 http://www.xgezhang.com/python_scrapy_redis_crawler.html 爬虫技术,无论是在学术领域,还是在工程领域,都扮演者非常重要的角色.相比于其他 ...
随机推荐
- Go JSON 转化规则
Go语言内置encoding/json包支持JSON序列化和反序列化,有如下转换规则 基本的数据结构映射关系 bool, for JSON booleans float64, for JSON num ...
- Swagger2 添加HTTP head参数
大家使用swagger往往会和JWT一起使用,而一般使用jwt会将token放在head里,这样我们在使用swagger测试的时候并不方便,因为跨域问题它默认不能自定义head参数.然后自己去网上找, ...
- 【Spark篇】---Spark初始
一.前述 Spark是基于内存的计算框架,性能要优于Mapreduce,可以实现hadoop生态圈中的多个组件,是一个非常优秀的大数据框架,是Apache的顶级项目.One stack rule ...
- 1.python简介
简介 1.python语言介绍 python的创始人:Guido Van Rossum 2.python是一门什么样的语言 编程语言主要从以下几个角度进行分类:编译型,静态型,动态性,强类型定义语言和 ...
- 有了这 4 大特性,CDN 好用到飞起
随着 CDN 市场的快速发展和网络新技术的不断涌现,目前的 CDN 已不仅仅是当初简单的内容分发,同时也是新特性研发.新技术推广及实践的平台.这些新技术.新特性,或者能够保障 CDN 安全性,或是提升 ...
- .NET Core实战项目之CMS 第十三章 开发篇-在MVC项目结构介绍及应用第三方UI
作为后端开发的我来说,前端表示真心玩不转,你如果让我微调一个位置的样式的话还行,但是让我写一个很漂亮的后台的话,真心做不到,所以我一般会选择套用一些开源UI模板来进行系统UI的设计.那如何套用呢?今天 ...
- .net core使用EasyNetQ做EventBus
随着SOA.微服务.CQRS的盛行,EventBus越来越流行,上GitHub搜了一下,还是有蛮多的这类实现,老牌的有NServiceBus(收费).MassTransit,最近的有CAP(国人写的, ...
- React Native (一) 入门实践
上周末开始接触react native,版本为0.37,边学边看写了个demo,语法使用es6/7和jsx.准备分享一下这个过程.之前没有native开发和react的使用经验,不对之处烦请指出.笔者 ...
- Config Server高可用
一 简介构建高可用的Config Server集群,包括Config Server的高可用,以及依赖Git仓库的高可用. 二 Git仓库的高可用由于配置的内容都存储在Git仓库中,所以要想实现Conf ...
- API网关模式
什么是网关 网关一词来源于计算机网络中的定义,网关(Gateway)又称网间连接器.协议转换器.网关的准确定义是: 两个计算机程序或系统之间的连接,网关作为两个程序之间的门户,允许它们通过不同计算机之 ...