zoukankan      html  css  js  c++  java
  • TinScrapy-简化的Scrapy原码-查看爬虫的执行流程

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

      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
  • 相关阅读:
    linux系统添加指定uid和gid的用户和组
    sshd服务安装
    psql: could not connect to server: No such file or directory&&PGHOST
    如何使用Python操纵Postgres数据库
    postgresql数据库常用操作命令及SQL语言
    Postgres安装
    Postgres 主从复制搭建步骤
    Centos7上安装docker
    MySQL 基本语法
    Redis-Migrate-Tool 使用详解
  • 原文地址:https://www.cnblogs.com/uge3/p/9226260.html
Copyright © 2011-2022 走看看