Django、Flask、scrapy都包含了一個「信號分配器」,使得當一些動做在框架的其餘地方發生的時候,解耦的應用能夠獲得提醒。html
通俗來說,就是一些動做發生的時候,信號容許特定的發送者去提醒一些接受者,這是特別有用的設計由於有些代碼對某些事件是特別感興趣的,好比刪除動做。python
下面,分別介紹一下三種信號的使用示例。sql
不少數狀況下,咱們須要在操做數據庫以前或者以後作某些操做,好比說寫個日誌之類的,咱們固然能夠找到每個sql語句,在其先後加一段代碼,數據庫
可是,這不但浪費時間,還爲之後的維護增長了難度,這個時候,就體現出信號的做用了。下面的代碼是Django中對數據庫增長一條數據的操做:django
# models.py from django.db import models class User(models.Model): title = models.CharField(max_length=32) # views.py from django.shortcuts import render,HttpResponse from app01 import models def func1(request): models.User.objects.create(title='付勇') return HttpResponse('建立成功') def func2(request): models.User.objects.create(title='小男孩') return HttpResponse('建立成功') def func3(request): models.User.objects.create(title='小少年') return HttpResponse('建立成功') def func4(request): models.User.objects.create(title='小青年') return HttpResponse('建立成功')
這個時候,若是咱們想要在每增長一條數據以後在控制檯打印一句話(固然能夠換成其餘操做)的話,就能夠在項目下的__init__.py中進行信號操做,代碼以下:flask
from django.db.models import signals def before_save1(*args,**kwargs): print('before_save1--->',args,kwargs) def before_save2(*args,**kwargs): print('before_save2--->',args,kwargs) def after_save1(*args,**kwargs): print('after_save2---->',args,kwargs) # 在增長數據以前執行before_save1函數 signals.pre_save.connect(before_save1) # 在增長數據以前執行before_save2函數 signals.pre_save.connect(before_save2) # 在增長數據以後執行after_save1函數 signals.post_save.connect(after_save1)
Django中的內置信號:app
Model signals pre_init # django的modal執行其構造方法前,自動觸發 post_init # django的modal執行其構造方法後,自動觸發 pre_save # django的modal對象保存前,自動觸發 post_save # django的modal對象保存後,自動觸發 pre_delete # django的modal對象刪除前,自動觸發 post_delete # django的modal對象刪除後,自動觸發 m2m_changed # django的modal中使用m2m字段操做第三張表(add,remove,clear)先後,自動觸發 class_prepared # 程序啓動時,檢測已註冊的app中modal類,對於每個類,自動觸發 Management signals pre_migrate # 執行migrate命令前,自動觸發 post_migrate # 執行migrate命令後,自動觸發 Request/response signals request_started # 請求到來前,自動觸發 request_finished # 請求結束後,自動觸發 got_request_exception # 請求異常後,自動觸發 Test signals setting_changed # 使用test測試修改配置文件時,自動觸發 template_rendered # 使用test測試渲染模板時,自動觸發 Database Wrappers connection_created # 建立數據庫鏈接時,自動觸發
項目功能複雜,代碼量越大,就越須要作業務解耦。不然在其之上作開發和維護是很痛苦的,尤爲是對於團隊的新人。框架
Flask從0.6開始,經過Blinker提供了信號支持。信號就是在框架核心功能或者一些Flask擴展發生工做時所發送的通知,用於幫助你解耦應用。scrapy
若是須要在Flask中使用信號,須要先安裝blinker組件:ide
pip install blinker
使用信號代碼以下:
from flask import Flask,render_template from flask import signals app = Flask(__name__) def x1(arg): print('x1') def x2(arg): print('x2') # 在發起請求以前執行x1函數 signals.request_started.connect(x1) # 在發起請求以前執行x2函數 signals.request_started.connect(x2) @app.route('/index') def func(): print('視圖函數') return "ok" if __name__ == '__main__': app.run()
Flask中內置的信號:
1. template_rendered:模版渲染完成後的信號。 2. before_render_template:模版渲染以前的信號。 3. request_started:模版開始渲染。 4. request_finished:模版渲染完成。 5. request_tearing_down:request對象被銷燬的信號。 6. got_request_exception:視圖函數發生異常的信號。通常能夠監聽這個信號,來記錄網站異常信息。 7. appcontext_tearing_down:app上下文被銷燬的信號。 8. appcontext_pushed:app上下文被推入到棧上的信號。 9. appcontext_popped:app上下文被推出棧中的信號 10. message_flashed:調用了Flask的`flashed`方法的信號。
Scrapy使用信號來通知事情發生。您能夠在您的Scrapy項目中捕捉一些信號(使用 extension)來完成額外的工做或添加額外的功能,擴展Scrapy。
雖然信號提供了一些參數,不過處理函數不用接收全部的參數 - 信號分發機制(singal dispatching mechanism)僅僅提供處理器(handler)接受的參數。
使用的時候新建一個py文件,如ext.py,代碼以下:
from scrapy import signals class MyExtend(object): def __init__(self): pass @classmethod def from_crawler(cls, crawler): self = cls() # 爬蟲啓動的時候執行x1方法 crawler.signals.connect(self.x1, signal=signals.spider_opened) # 爬蟲啓動的時候執行x2方法 crawler.signals.connect(self.x2, signal=signals.spider_closed) return self def x1(self, spider): print('open') def x2(self, spider): print('close')
Scrapy內置的信號:
engine_started scrapy.signals.engine_started() 當scrapy引擎啓動爬取時發送該信號 該信號支持返回deferreds 當信號可能會在信號spider_opened以後被髮送,取決於spider的啓動方式 engine_stopped scrapy.signals.engine_stopped() 當scrapy引擎中止時發送該信號例如爬取結束 該信號支持返回deferreds item_scraped scrapy.signals.item_scrapped(item,response,spider) 當item被爬取,並經過Item Pipeline後沒有被dropped時發送,該信號支持返回deferreds 參數:爬取到的item對象 爬取item的spider對象 提取item的response對象 item_dropped scrapy.signals.item_dropped(item,exception,spider) 當item經過Item Pipeline,有些pipeline拋出DropItem異常,丟棄item時發送,該信號支持返回deferreds 參數:Item Pipeline丟棄的item 爬取item的spider對象 致使item被丟棄的異常,必須是DropItem的子類 spider_closed scrapy.signals.spider_closed(spider,reason) 當某個spider被關閉時發送,該信號能夠用來釋放每一個spider在spider_opened後佔用的資源 該信號支持返回deferreds 參數:被關閉的spider對象 描述spider被關閉的緣由的字符串。若是spider是因爲完成爬取而被關閉,則其爲‘finished'。若是spider是被引擎的close_spider方法所關閉,則其爲調用該方法時的reason參數(默認爲'cancelled')。若是引擎被關閉好比輸入Ctrl + C ,則爲'shutdown' spider_opened scrapy.signals.spider_opened(spider) 當spider開始爬取時發送該信號。該信號支持返回deferreds 參數:開啓的spider對象 spider_idle scrapy.signals.spider_idle(spider) 當spider進入空閒狀態時發送該信號。 空閒意味着:requests正在等待被下載 requests被調度 items正在item pipeline中處理 當該信號的全部處理器handler被調用後,若是spider仍然保持空閒狀態,引擎將會關閉該spider。當spider被關閉後,spider_closed信號將被髮送 能夠在spider_idle處理器中調度某些請求來避免spider被關閉。該信號不支持返回deferreds 參數:空閒的spider對象 spider_error scrapy.signals.spider_error(failure,response,spider) 當spider的回調函數產生錯誤時發送該信號 參數:以Twisted Failure對象拋出的異常 當異常被拋出時被處理的response對象 拋出異常的spider對象 request_scheduled scrapy.signals.request_scheduled(request,spider) 當引擎調度一個request對象用於下載時,該信號被髮送,該信號不支持返回deferreds 參數:到達調度器的request對象 產生該request的spider對象 response_received scrapy.signals.response_received(response,request,spider) 當引擎從downloader獲取一個新的response時發送該信號,該信號不支持返回deferreds 參數:接受的response對象 生成response的request對象 response對應的spider對象 response_downloaded scrapy.siganls.response_downloaded(response,request,spider) 當一個HttpResponse被下載時,由downloader發送該信號,該信號不支持返回deferreds 參數:下載的response對象 生成response的request對象 response對應的spider對象