欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

TinScrapy-简化的Scrapy原码-查看爬虫的执行流程

程序员文章站 2022-06-30 13:45:28
学习了自定义的TinyScrapy框架,整理出以下定注释的代码 1 from twisted.web.client import getPage,defer 2 from twisted.internet import reactor 3 import queue 4 5 class Respons ......

 

学习了自定义的TinyScrapy框架,整理出以下定注释的代码

TinScrapy-简化的Scrapy原码-查看爬虫的执行流程
  1 from twisted.web.client import getPage,defer
  2 from twisted.internet import reactor
  3 import queue
  4 
  5 class Response(object):
  6     '''
  7     对返回内容进行封装为UTF8格式
  8     '''
  9     def __init__(self,body,request):
 10         self.body=body
 11         self.request=request
 12         self.url=request.url
 13 
 14     @property
 15     def text(self):
 16         return self.body.decode('utf-8')
 17 
 18 class Request(object):
 19     '''
 20     封装,请求的URL 与回调函数
 21     '''
 22     def __init__(self,url,callback):
 23         self.url=url
 24         self.callback=callback
 25 
 26 class Scheduler(object):#调度器
 27     '''
 28     任务调度器
 29     '''
 30     def __init__(self,engine):
 31         self.q=queue.Queue()#队列
 32         self.engine=engine
 33     def enqueue_request(self,request):
 34         self.q.put(request)#加入队列
 35     def next_request(self):
 36         try:
 37             req=self.q.get(block=False)#从队列中取出
 38         except Exception as e:
 39             req=None
 40         return req
 41     def size(self):
 42         return self.q.qsize()#队列是的个数
 43 
 44 class ExecutionEngine(object): #爬虫引擎
 45 
 46     def __init__(self):#构造
 47         self._closewait=None #关闭引擎调用 默认为不关闭
 48         self.running=True#引擎默认为运行状态
 49         self.start_requests=None #开始爬取任务
 50         self.scheduler=Scheduler(self)#调度器 类 构造自己放入调度器,传回自身
 51         self.inprogress =set() #集合 并发数
 52 
 53     def check_empty(self,response):#检测任务是否为空
 54         if not self.running:
 55             print('任务终止。。。。')
 56             self._closewait.callback(None)
 57 
 58     def _next_request(self):#下一个爬取任务
 59         while self.start_requests:#存在爬取任务
 60             try:
 61                 request=next(self.start_requests)
 62             except StopIteration:#如果执行出错
 63                 self.start_requests=None#任务变为空
 64             else:
 65                 self.scheduler.enqueue_request(request)#放入调度器中
 66         print(len(self.inprogress),'=>总任务数',self.scheduler.size(),'=>调度器中的任务数')
 67         while len(self.inprogress)< 5 and self.scheduler.size()>0: #最大并发数为 5
 68             request=self.scheduler.next_request()#调度器中任务 调用自身
 69             if not request:
 70                 break
 71             self.inprogress.add(request)#加入任务并发
 72             d=getPage(bytes(request.url,encoding='utf-8'))#开始爬取任务
 73             #d.addError=()#任务出错时执行
 74             #d.addCallback=()#任务成功完成时执行
 75             d.addBoth(self._handle_downloader_output,request)#下载 任务 #无论是否成功都执行 有返回值 运行_handle
 76             d.addBoth(lambda x,req:self.inprogress.remove(req),request)#正在运行的进行移除
 77             d.addBoth(lambda x:self._next_request())#执行本身的函数
 78         if len(self.inprogress)==0 and self.scheduler.size()==0:
 79             self._closewait.callback(None)#执行关闭程序
 80 
 81     def _handle_downloader_output(self,body,request):#任务后的回调函数
 82         '''
 83         获取内容,执行回调函数,并且把回调函数中的返回值获取,并添加到队列中
 84         :param response:
 85         :param request:
 86         :return:
 87         '''
 88         import  types
 89         response=Response(body,request)#进行封装
 90         func=request.callback or self.spider.parse#如果有回返值,func取回返值 否则 等于任务的最开始内容
 91         gen=func(response)
 92         if isinstance(gen,types.GeneratorType):#是否是生成器对象
 93             for req in gen:
 94                 self.scheduler.enqueue_request(req)
 95 
 96     @defer.inlineCallbacks
 97     def start(self):
 98         self._closewait=defer.Deferred()#生成一个空任务对象 用于保持程序
 99         yield self._closewait
100 
101     @defer.inlineCallbacks
102     def open_spider(self,spider,start_requests):#传入封装好的Requset ,任务迭代器
103         self.start_requests=start_requests#任务迭代器
104         self.spider=spider#封装好的Requset (请求的URL 与回调函数)
105         yield None #生成器,断点缓存
106         reactor.callLater(0,self._next_request)#立刻执行 下一个爬取任务
107 
108 class Crawler(object):#爬虫执行类
109     def __init__(self,spidercls):#传入任务(ChoutiSpider,等)
110         self.spidercls=spidercls
111         self.spider =None
112         self.engine=None
113 
114     @defer.inlineCallbacks
115     def crawl(self):
116         self.engine=ExecutionEngine()#类实例化 引擎
117         self.spider=self.spidercls()#实例化任务
118         start_requests =iter(self.spider.start_requests())#迭代器
119         yield self.engine.open_spider(self.spider,start_requests)#引擎启动
120         yield self.engine.start()#开始执行
121 
122 class CrawlerProcess(object):#爬虫任务器 类
123     def __init__(self):
124         self._active=set()#已经执行任务集合
125         self.crawlers=set()# 爬虫任务集合
126 
127     def crawl(self,spidercls,*args,**kwargs):#传入爬虫任务
128         crawler=Crawler(spidercls)#爬虫任务开始  实例化
129         self.crawlers.add(crawler)#爬虫任务集合
130         d=crawler.crawl(*args,**kwargs)#爬取任务实例化 运行
131         self._active.add(d)#加入已经执行任务集合
132         return d
133 
134     def start(self):
135         d1=defer.DeferredList(self._active)#实例化执行对象
136         d1.addBoth(self._stop_reactor)#所有任务结束 调用 stop方法
137         reactor.run()
138 
139     def _stop_reactor(self,_=None):#任务停止
140         reactor.stop()
141 
142 class Spider(object):
143     def start_requests(self):
144         for url in self.start_urls:
145             yield  Request(url,self.parse)#生成器,对URL与回调函数进行封装
146 
147 #=========具体爬虫任务=======start==========#
148 class ChoutiSpider(Spider):#
149     name='chouti'
150     start_urls=['http://dig.chouti.com/',]
151     def parse(self,response):
152         print(response.text)
153 
154 class CnblogsSpider(Spider):
155     name='cnblogs'
156     start_urls=['http://www.cnblogs.com/',]
157     def parse(self,response):
158         print(response.text)
159 #=========具体爬虫任务=======end==========#
160 
161 if __name__=='__main__':
162     spider_cls_list=[ChoutiSpider,CnblogsSpider]#加入任务列表
163     crawler_process=CrawlerProcess()#实例化爬虫任务器
164     for spider_cls in spider_cls_list:
165         crawler_process.crawl(spider_cls)#传入任务
166     crawler_process.start()#开始执行
TinyScrapy