学习了自定义的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原码-查看爬虫的执行流程的更多相关文章

  1. Yii2 源码分析 入口文件执行流程

    Yii2 源码分析  入口文件执行流程 1. 入口文件:web/index.php,第12行.(new yii\web\Application($config)->run()) 入口文件主要做4 ...

  2. asyncio源码分析之基本执行流程

    基于async关键字的原生协程 # 定义一个简单的原生协程cor async def cor(): print('enter cor') print('exit cor') print(type(co ...

  3. 【推理引擎】从源码看ONNXRuntime的执行流程

    目录 前言 准备工作 构造 InferenceSession 对象 & 初始化 让模型 Run 总结 前言 在上一篇博客中:[推理引擎]ONNXRuntime 的架构设计,主要从文档上对ONN ...

  4. 浩哥解析MyBatis源码(一)——执行流程

    原创作品,可以转载,但是请标注出处地址: 一.MyBatis简介 MyBatis框架是一种轻量级的ORM框架,当下十分流行,配合Spring+Spring MVC组成SSM框架,能够胜任几乎所有的项目 ...

  5. Mybatis 系列10-结合源码解析mybatis 的执行流程

    [Mybatis 系列10-结合源码解析mybatis 执行流程] [Mybatis 系列9-强大的动态sql 语句] [Mybatis 系列8-结合源码解析select.resultMap的用法] ...

  6. scrapy 6023 telnet查看爬虫引擎相关状态

    Telnet终端(Telnet Console) Scrapy提供了内置的telnet终端,以供检查,控制Scrapy运行的进程. telnet仅仅是一个运行在Scrapy进程中的普通python终端 ...

  7. Flask源码解析:Flask应用执行流程及原理

    WSGI WSGI:全称是Web Server Gateway Interface,WSGI不是服务器,python模块,框架,API或者任何软件,只是一种规范,描述服务器端如何与web应用程序通信的 ...

  8. 通过更改scrapy源码进行spider分发实现一个综合爬虫

    最近我正写一个项目,项目的需求如下一,要爬取大约100种几百个网页的类容,并且这些网页的爬取频率不一样,有些一天爬取一次,有些一周爬取一次,二,网页爬取内容有变化,也就是说要爬取的内容会根据需求进行改 ...

  9. 基于Python,scrapy,redis的分布式爬虫实现框架

    原文  http://www.xgezhang.com/python_scrapy_redis_crawler.html 爬虫技术,无论是在学术领域,还是在工程领域,都扮演者非常重要的角色.相比于其他 ...

随机推荐

  1. [Swift]LeetCode945. 使数组唯一的最小增量 | Minimum Increment to Make Array Unique

    Given an array of integers A, a move consists of choosing any A[i], and incrementing it by 1. Return ...

  2. linux入门--Linux系统的优缺点

    1) 大量的可用软件及免费软件 Linux 系统上有着大量的可用软件,且绝大多数是免费的,比如声名赫赫的 Apache.Samba.PHP.MySQL 等,构建成本低廉,是 Linux 被众多企业青睐 ...

  3. Kubernetes---pod--重启策略

    restartPolicy: Always: 默认 , 总是重启 OnFailure : 错误事重启 Never: 从来不重启 Default  to Always:

  4. 如何随机排序数组?使用多种方式!递归,迭代,洗牌,sort方法!

    方式1: 使用sort 方法 ---- // 方法1 使用sort 方法 var arr = [1,2,3,4,5,6,7,8]; function foo(arr) { var cloneArr = ...

  5. Spring之AOP流程解析(ProxyFactory)

    本节我们从ProxyFactory开始分析.该类有几个比较重要的方法——addAdvice.addAdvisor.getProxy,其中最后一个方法是我们本节的重点.前两个方法都是向ProxyFact ...

  6. Java中需要知道的关键字

    Java中有一些或常用,或不常用,但却不得不知关键字,本篇文章将讨论这些关键字的作用. transient transient关键字可能用的不是那么频繁,但却是一个很重要的关键字,它的作用是在对象序列 ...

  7. 项目总结四:神经风格迁移项目(Art generation with Neural Style Transfer)

    1.项目介绍 神经风格转换 (NST) 是深部学习中最有趣的技术之一.它合并两个图像, 即 内容图像 C(content image) 和 样式图像S(style image), 以生成图像 G(ge ...

  8. 低延时的P2P HLS直播技术实践

    本文根据4月21日OSC源创会·武汉站的现场分享为蓝本,重新整理.以下是演讲内容: 近几年,随着直播.短视频等视频领域对带宽要求的提升以及CDN行业竞争的加剧,很多CDN公司开始往P2P-CDN方向发 ...

  9. 外接程序 VMDebugger 未能加载或导致了异常 修复

    单击进入 是 visual studio   在 VMWARE 菜单栏上 单击 右键,出现如图,然后选择  自定义(C)...   打开 自定义 工具栏 里 选中 VMware 然后单击 删除 按钮 ...

  10. 带着萌新看springboot源码13(手写一个自己的starter)

    springboot的最强大的就是那些xxxAutoconfiguration,但是这些xxxAutoConfiguration又依赖那些starter,只有导入了这些场景启动器(starter),我 ...