Python用yield form 實現異步協程爬蟲

很古老的用法了,現在大多用的aiohttp庫實現,這篇記錄僅僅用做個人的協程底層實現的學習 。爭取用看得懂的字來描述問題 。
1.什么是yield如果還沒有怎么用過的話,直接把yield看做成一種特殊的return(PS:本質 generator(生成器))return是返回一個值然后就終斷函數了,而yield返回的是一個生成器(PS:不知道的直接看作特殊列表,看下面的代碼案例)
# -*- coding: utf-8 -*-# @Time    : 2022/11/10 16:17# @Author  : 紅后# @Email   : not_enabled@163.com# @blog    : https://www.cnblogs.com/Red-Sun# @File    : 實例1.py# @Software: PyCharmdef main():    '''    遍歷0到4,這五個數,并分別打印    '''    for num in range(5):        yield numif __name__ == '__main__':    for num in main():        print(num)    print('-'*50)    for num in [0, 1, 2, 3, 4]:        print(num)將它看作列表用for循環遍歷,就能取出其中的值 。
2.yield于列表的區別它與原來列表的區別就在于 , 自帶的列表是固定的,而把yield看作列表的話是動態的 。具體案例描述請看代碼及備注(PS:個人自己描述的,有不對的地方望各位指點)
# -*- coding: utf-8 -*-# @Time    : 2022/11/14 13:24# @Author  : 紅后# @Email   : not_enabled@163.com# @blog    : https://www.cnblogs.com/Red-Sun# @File    : 實例2.py# @Software: PyCharmdef main():    '''    將yield看作一個動態列表,從yield左往右為傳出數據,從又往左為傳入數據 。    PS:有yield存在的那一行 , 需要從左往右傳出數據跑一遍,數據出去以后又要從又往左帶接收的數據跑一遍,一共一行跑兩邊(僅作者個人記憶方法)    '''    num1 = yield    num2 = yield    print(num1, num2)    yield num1 + num2if __name__ == '__main__':    a = main()    # 第一個next對應第一個yield的右邊為空即None,所以動態列表中加入一個參數為None,返回值為列表的-1位是None    print(next(a))  # [None]    # 第二個通過send方法傳入一個數1,即在上一次停止的地方從右往左傳入參數 , 所以給num1賦值為1.然后繼續找下一個yield,其右邊的值依舊為None,加入動態列表 , 此時返回值-1位依舊是None    print(a.send(1))  # [None, None]    # 第三通過send方法傳入一個數2,即在上一次停止的地方從右往左傳入參數,所以給num2賦值為2.然后繼續找下一個yield,其右邊的值為num1 + num2,此時num1為1 , num2為2,計算得返回值-1位為3    print(a.send(2))  # [None, None, num1 + num2]3.yield from 實現協程yield from 后面需要加可迭代對象當它后面加上生成器(上述所說的yield這種)便可以實現生成的嵌套

  1. 老板(主程序):調用委派生成器
  2. 包工頭(委派生成器):包含yield from表達式的生成器
  3. 打工仔(子生成器):生成器函數
其中委派生成器的作用:在主程序與子生成器之間建立一個雙向通道 。所謂雙向通道是指,主程序可以將參數通過send傳遞給子生成器,子生成器的yield的值也可以直接返回給主函數 。(PS:委派生成器只有創建通道的作用 , 沒有攔截數據這種功能)也許有人會想直接用主程序調用子生成器不就行了,而對這的解釋是,使用yield from作為中間過渡是為了讓它幫我們進行異常處理(PS:類似寫程序為了正常運行加上try一個道理)
# -*- coding: utf-8 -*-# @Time    : 2022/11/10 15:13# @Author  : 紅后# @Email   : not_enabled@163.com# @blog    : https://www.cnblogs.com/Red-Sun# @File    : coroutines.py# @Software: PyCharmimport requestsdef coroutines_spider():    '''    子生成器(PS: 打工仔,真正干活的)    '''    response = None  # 首次激活返回None,后期網頁響應覆蓋    while True:        url = yield response        response = requests.get(url)def appoint():    '''    委派生成器,委托子生成器完成具體任務 (PS: 類似包工頭負責勞務派遣)    '''    while True:        yield from coroutines_spider()  # 建立子生成器和主函數的雙通道def main(url_list: list):    '''    主函數(PS: 相當于老板 , 張貼招人啟示)    '''    ul = appoint()  # 創建委派生成器    next(ul)  # 激活它    for url in url_list:        response = ul.send(url)  # 將url作為參數傳遞進入子生成器中,返回子生成器yield出來的response        print(response.url, response.status_code)  # 打印出response中的鏈接和狀態碼if __name__ == '__main__':    url_list = ['https://www.baidu.com/', 'https://www.4399.com/', 'https://cn.bing.com/', ]    main(url_list=url_list

推薦閱讀