您现在的位置是:首页 > 编程语言学习 > 其他编程语言 > 文章正文 其他编程语言

Python利用yield form实现异步协程爬虫

2022-11-15 10:31:02 其他编程语言

简介很古老的用法了,现在大多用的aiohttp库实现,这篇记录仅仅用做个人的协程底层实现的学习。争取用看得懂的字来描述问题。1.什么是yield如果...

很古老的用法了,现在大多用的aiohttp库实现,这篇记录仅仅用做个人的协程底层实现的学习。

争取用看得懂的字来描述问题。

1.什么是yield

如果还没有怎么用过的话,直接把yield看做成一种特殊的return(PS:本质 generator(生成器))return是返回一个值然后就终断函数了,而yield返回的是一个生成器(PS:不知道的直接看作特殊列表,看下面的代码案例)

  1. # -*- coding: utf-8 -*- 
  2. # @Time: 2022/11/10 16:17 
  3. # @Author  : 红后 
  4. # @Email   : not_enabled@163.com 
  5. # @blog: https://www.cnblogs.com/Red-Sun 
  6. # @File: 实例1.py 
  7. # @Software: PyCharm 
  8.  
  9. def main(): 
  10. ''
  11. 遍历0到4,这五个数,并分别打印 
  12. ''
  13. for num in range(5): 
  14. yield num 
  15.  
  16. if __name__ == '__main__'
  17. for num in main(): 
  18. print(num) 
  19. print('-'*50) 
  20. for num in [0, 1, 2, 3, 4]: 
  21. print(num) 

将它看作列表用for循环遍历,就能取出其中的值。

2.yield于列表的区别

它与原来列表的区别就在于,自带的列表是固定的,而把yield看作列表的话是动态的。

具体案例描述请看代码及备注(PS:个人自己描述的,有不对的地方望各位指点)

  1. # -*- coding: utf-8 -*- 
  2. # @Time: 2022/11/14 13:24 
  3. # @Author  : 红后 
  4. # @Email   : not_enabled@163.com 
  5. # @blog: https://www.cnblogs.com/Red-Sun 
  6. # @File: 实例2.py 
  7. # @Software: PyCharm 
  8.  
  9. def main(): 
  10. ''
  11. 将yield看作一个动态列表,从yield左往右为传出数据,从又往左为传入数据。 
  12. PS:有yield存在的那一行,需要从左往右传出数据跑一遍,数据出去以后又要从又往左带接收的数据跑一遍,一共一行跑两边(仅作者个人记忆方法) 
  13. ''
  14. num1 = yield 
  15. num2 = yield 
  16. print(num1, num2) 
  17. yield num1 + num2 
  18. if __name__ == '__main__'
  19. a = main() 
  20. # 第一个next对应第一个yield的右边为空即None,所以动态列表中加入一个参数为None,返回值为列表的-1位是None 
  21. print(next(a))  # [None] 
  22. # 第二个通过send方法传入一个数1,即在上一次停止的地方从右往左传入参数,所以给num1赋值为1.然后继续找下一个yield,其右边的值依旧为None,加入动态列表,此时返回值-1位依旧是None 
  23. print(a.send(1))  # [None, None] 
  24. # 第三通过send方法传入一个数2,即在上一次停止的地方从右往左传入参数,所以给num2赋值为2.然后继续找下一个yield,其右边的值为num1 + num2,此时num1为1,num2为2,计算得返回值-1位为3 
  25. print(a.send(2))  # [None, None, num1 + num2] 

3.yield from 实现协程

yield from 后面需要加可迭代对象

当它后面加上生成器(上述所说的yield这种)便可以实现生成的嵌套

  • 老板(主程序):调用委派生成器
  • 包工头(委派生成器):包含yield from表达式的生成器
  • 打工仔(子生成器):生成器函数

其中委派生成器的作用:在主程序与子生成器之间建立一个双向通道。

所谓双向通道是指,主程序可以将参数通过send传递给子生成器,子生成器的yield的值也可以直接返回给主函数。(PS:委派生成器只有创建通道的作用,没有拦截数据这种功能)

也许有人会想直接用主程序调用子生成器不就行了,而对这的解释是,使用yield from作为中间过渡是为了让它帮我们进行异常处理(PS:类似写程序为了正常运行加上try一个道理)

  1. # -*- coding: utf-8 -*- 
  2. # @Time: 2022/11/10 15:13 
  3. # @Author  : 红后 
  4. # @Email   : not_enabled@163.com 
  5. # @blog: https://www.cnblogs.com/Red-Sun 
  6. # @File: coroutines.py 
  7. # @Software: PyCharm 
  8.  
  9. import requests 
  10.  
  11.  
  12. def coroutines_spider(): 
  13. ''
  14. 子生成器(PS: 打工仔,真正干活的) 
  15. ''
  16. response = None  # 首次激活返回None,后期网页响应覆盖 
  17. while True: 
  18. url = yield response 
  19. response = requests.get(url) 
  20.  
  21.  
  22. def appoint(): 
  23. ''
  24. 委派生成器,委托子生成器完成具体任务 (PS: 类似包工头负责劳务派遣) 
  25. ''
  26. while True: 
  27. yield from coroutines_spider()  # 建立子生成器和主函数的双通道 
  28.  
  29.  
  30. def main(url_list: list): 
  31. ''
  32. 主函数(PS: 相当于老板,张贴招人启示) 
  33. ''
  34. ul = appoint()  # 创建委派生成器 
  35. next(ul)  # 激活它 
  36. for url in url_list: 
  37. response = ul.send(url)  # 将url作为参数传递进入子生成器中,返回子生成器yield出来的response 
  38. print(response.url, response.status_code)  # 打印出response中的链接和状态码 
  39.  
  40.  
  41. if __name__ == '__main__'
  42. url_list = ['https://www.baidu.com/''https://www.4399.com/''https://cn.bing.com/', ] 
  43. main(url_list=url_list) 

相关文章

站点信息