1.调度器

class Scheduler(object):
"""调度器"""
def __init__(self, engine):
"""
:param engine:引擎
"""
self.q = queue.Queue()
self.engine = engine def put(self, request):
self.q.put(request) def get(self):
try:
req = self.q.get(block=False)
except Exception as e:
req = None
return req def size(self):
return self.q.qsize()

利用队列实现调度器功能

2.引擎

class Engine(object):
"""引擎"""
def __init__(self, max=5):
"""
:param max: 最大并发数
"""
self._close = None  #用于defered对象的关闭
self.max = max
self.crawling = []  #存储正在进行处理的request
self.scheduler = Scheduler(self)  #实例化调度器 def get_response_callback(self, content, request):
     """
      1.将此request从self.crawing中删除
      2.执行爬虫对象中的回调函数
      3.若返回的结果是一个生成器,则将其遍历,并且添加到调度器中
     """
self.crawling.remove(request)
result = request.callback(content)
if isinstance(result, types.GeneratorType):
for req in result:
self.scheduler.put(req) def _next_request(self):
     """
     1.判断调度器中队列的大小是否为0和正在处理的request个数,若都为0,则表明爬虫执行完毕,self._close.callback(None)关闭Deferred对象
     2.当处理中的request数大于或等于最大并发数时,让后续等待
     3.当处理中的request数小于最大并发数时,从调度器中调取任务,并添加到self.crawling中,利用getPage下载页面,并为此对象添加回调函数get_response_callback
     4.处理完成后添加回调函数_next_request,继续下一个任务的处理
     """
if self.scheduler.size() == 0 and len(self.crawling) == 0:
self._close.callback(None)
return
if len(self.crawling) >= self.max:
return
while len(self.crawling) < self.max:
req = self.scheduler.get()
if req is None:
return
self.crawling.append(req) d = getPage(req.url.encode('utf-8'))
d.addCallback(self.get_response_callback, req)
d.addCallback(lambda _: reactor.callLater(0, self._next_request))

3.爬虫对象

class Crawler(object):
"""爬虫对象"""
def __init__(self, spidercls):
"""
:param spidercls:爬虫类
"""
self.spidercls = spidercls  
self.spider = None  #爬虫
self.engine = None  #引擎 @defer.inlineCallbacks  
def crawl(self):
     """
      1.start_request 爬取的网页地址生成器
      2.获取url,并添加到调度器中
      3.执行self,engine._next_request()来处理request
      4.self.engine._close赋值为一个Deferred对象
     """
self.engine = Engine()
self.spider = self.spidercls()
start_request = iter(self.spider.start_requests())
while 1:
try:
request = next(start_request)
self.engine.scheduler.put(request)
except StopIteration as e:
break
self.engine._next_request()
self.engine._close = defer.Deferred()
yield self.engine._close
@defer.inlineCallbacks装饰器,被装饰函数必须是一个生成器
Deferred对象是一个类似于Socket对象的一个无限循环的对象,应用程序将一连串函数添加到Deferred对象中,当异步请求的结果准备就绪时,这一连串函数将被按顺序调用(这一连串函数被称为一个callback序列,或是一
条callback链),一起添加的还有另外一连串函数,当异步请求出现错误的时候,他们将被调用(称作一个errback序列,或是一条errback链)。异步库代码会在结果准备就绪时,调用第一个callback,或是在出现错误时,
调用第一个errback,然后Deferred对象就会将callback或errback的返回结果传递给链中的下一个函数。

4.爬虫进程

class CrawlProcess(object):
"""爬虫进程"""
def __init__(self):
self._active = []    #存储每一个Deferred对象
self.crawlers = []    #要执行的爬虫的集合 def crawl(self, spidercls):
    """
      实例化Crawler,获得爬虫对象,每一个都执行crawl函数,添加到_active,实现后续并发
    """
crawler = Crawler(spidercls,)
self.crawlers.append(crawler)
d = crawler.crawl()
self._active.append(d)
return d def start(self):
     """
      开始处理Deferred对象,当所有的Deferred对象的回调函数都被触发,利用callback(None)结束之后,执行匿名函数关闭reactor
     """
dd = defer.DeferredList(self._active)
dd.addBoth(lambda _: reactor.stop())
reactor.run()

爬虫的实例化,和爬取工作的开启

5.Request

class Request(object):
def __init__(self, url, callback):
"""
:param url: 网址
:param callback:回调函数
"""
self.url = url
self.callback = callback

用于存储爬虫每一个url与其对应的处理函数。

6.main

if __name__ == '__main__':
spider_cls_list = []        #添加爬虫类名
crawler_process = CrawlProcess()
for spider_cls in spider_cls_list:
crawler_process.crawl(spider_cls)
crawler_process.start()

7.spider

class XXXSpider(object):

    name = XXX'

    def start_requests(self):
start_url = []
for url in start_url:
yield Request(url, self.parse) def parse(self, response):
print(response)

爬虫类格式,parse为回调函数,后续还能继续添加回调函数

爬虫之进阶 基于twisted实现自制简易scrapy框架(便于对scrapy源码的理解)的更多相关文章

  1. (转载)基于Unity~UGUI的简单UI框架(附UIFramework源码)

    此博客跟随siki老师的课程笔记生成,感谢siki老师的辛勤付出! 此框架功能较简单,适用于学习,可以很好的锻炼我们的设计思想 框架源码地址: UIFramework litjson.dll下载地址: ...

  2. 基于双向BiLstm神经网络的中文分词详解及源码

    基于双向BiLstm神经网络的中文分词详解及源码 基于双向BiLstm神经网络的中文分词详解及源码 1 标注序列 2 训练网络 3 Viterbi算法求解最优路径 4 keras代码讲解 最后 源代码 ...

  3. 基于Docker的TensorFlow机器学习框架搭建和实例源码解读

    概述:基于Docker的TensorFlow机器学习框架搭建和实例源码解读,TensorFlow作为最火热的机器学习框架之一,Docker是的容器,可以很好的结合起来,为机器学习或者科研人员提供便捷的 ...

  4. 爬虫(十四):Scrapy框架(一) 初识Scrapy、第一个案例

    1. Scrapy框架 Scrapy功能非常强大,爬取效率高,相关扩展组件多,可配置和可扩展程度非常高,它几乎可以应对所有反爬网站,是目前Python中使用最广泛的爬虫框架. 1.1 Scrapy介绍 ...

  5. Node 进阶:express 默认日志组件 morgan 从入门使用到源码剖析

    本文摘录自个人总结<Nodejs学习笔记>,更多章节及更新,请访问 github主页地址.欢迎加群交流,群号 197339705. 章节概览 morgan是express默认的日志中间件, ...

  6. python爬虫---scrapy框架爬取图片,scrapy手动发送请求,发送post请求,提升爬取效率,请求传参(meta),五大核心组件,中间件

    # settings 配置 UA USER_AGENT = 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, l ...

  7. OpenCV 基于超像素分割的图像区域选取方法及源码

    本系列文章由 @yhl_leo 出品,转载请注明出处. 文章链接: http://blog.csdn.net/yhl_leo/article/details/51386993 工程源码GitHub: ...

  8. C#使用Xamarin开发可移植移动应用进阶篇(7.使用布局渲染器,修改默认布局),附源码

    前言 系列目录 C#使用Xamarin开发可移植移动应用目录 源码地址:https://github.com/l2999019/DemoApp 可以Star一下,随意 - - 说点什么.. 本篇..基 ...

  9. C#使用Xamarin开发可移植移动应用进阶篇(8.打包生成安卓APK并精简大小),附源码

    前言 系列目录 C#使用Xamarin开发可移植移动应用目录 源码地址:https://github.com/l2999019/DemoApp 可以Star一下,随意 - - 说点什么.. 嗯,前面讲 ...

随机推荐

  1. E4A 与JS交互事件无反应

    今天碰到一个问题,E4A与JS的交互,调用JS函数后,事件没有任何反应,给JS赋值,会看到浏览框中有内容显示,但是事件为什么就没反应呢. 把官方的例程打开编译试了也不行. 后来在群中问了,原来是这里设 ...

  2. ssh:22端口拒绝服务

    在Hadoop配置中,被这个问题坑的死去活来的.总结一下,注意以下几点: 1.sshd是否启动.一般你ssh loaclhost的时候22端口拒绝,就很有可能是这个问题了. 手动打开:/etc/ini ...

  3. CPU的核、进程和线程

    转自https://www.cnblogs.com/-new/p/7234332.html 一.CPU与核心 物理核 物理核数量=cpu数(机子上装的cpu的数量)*每个cpu的核心数 虚拟核 所谓的 ...

  4. RN 各种小问题

    问题:vs code 无法启动 双击无反应 方法:控制台 输入 netsh winsock reset 重启 vs 问题:RN Debugger Network 不显示 源网页:https://git ...

  5. JavaScript 高级特性

    1. 原型Prototype 1.1 构造函数 所谓"构造函数",其实就是一个普通函数,但是内部使用了this变量.对构造函数使用new运算符,就能生成实例,并且this变量会绑定 ...

  6. 利用微信支付的订单查询接口可以在APP 中提高支付的可靠性

    最近公司有一个应用,用户可以在微信公众号上面下单,也可以在APP 中下单. 当用户在公共号上面下单时,微信支付成功可以返回微信支付单号,但是在APP 中用户微信支付时,个别时候会出现用户已经付款成功, ...

  7. Scrapy实战篇(七)之爬取爱基金网站基金业绩数据

    本篇我们以scrapy+selelum的方式来爬取爱基金网站(http://fund.10jqka.com.cn/datacenter/jz/)的基金业绩数据. 思路:我们以http://fund.1 ...

  8. DynamicEnumUtil 动态添加枚举类的枚举值

    import java.lang.reflect.AccessibleObject; import java.lang.reflect.Array; import java.lang.reflect. ...

  9. MAP File

    https://warpproject.org/trac/wiki/howto/Linker_scripts_MAP_files Description A MAP file is an output ...

  10. C#类与结构体的小结

    1.定义不同 类使用class关键字来定义: 结构体用struct: 2.使用时的注意事项 ->结构体是值类型,类是引用类型 ->结构体中声明的变量不能做赋值操作,但是类可以. -> ...