

Python用yield from 实现异步协程爬虫 - 红后
source link: https://www.cnblogs.com/Red-Sun/p/16889182.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

很古老的用法了,现在大多用的aiohttp库实现,这篇记录仅仅用做个人的协程底层实现的学习。
争取用看得懂的字来描述问题。
1.什么是yield
如果还没有怎么用过的话,直接把yield看做成一种特殊的return(PS:本质 generator(生成器))
return是返回一个值然后就终断函数了,而yield返回的是一个生成器(PS:不知道的直接看作特殊列表,看下面的代码案例)
# -*- coding: utf-8 -*-
# @Time : 2022/11/10 16:17
# @Author : 红后
# @Email : [email protected]
# @blog : https://www.cnblogs.com/Red-Sun
# @File : 实例1.py
# @Software: PyCharm
def main():
'''
遍历0到4,这五个数,并分别打印
'''
for num in range(5):
yield num
if __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 : [email protected]
# @blog : https://www.cnblogs.com/Red-Sun
# @File : 实例2.py
# @Software: PyCharm
def main():
'''
将yield看作一个动态列表,从yield左往右为传出数据,从又往左为传入数据。
PS:有yield存在的那一行,需要从左往右传出数据跑一遍,数据出去以后又要从又往左带接收的数据跑一遍,一共一行跑两边(仅作者个人记忆方法)
'''
num1 = yield
num2 = yield
print(num1, num2)
yield num1 + num2
if __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这种)便可以实现生成的嵌套
- 老板(主程序):调用委派生成器
- 包工头(委派生成器):包含yield from表达式的生成器
- 打工仔(子生成器):生成器函数
其中委派生成器的作用:在主程序与子生成器之间建立一个双向通道。
所谓双向通道是指,主程序可以将参数通过send传递给子生成器,子生成器的yield的值也可以直接返回给主函数。(PS:委派生成器只有创建通道的作用,没有拦截数据这种功能)
也许有人会想直接用主程序调用子生成器不就行了,而对这的解释是,使用yield from作为中间过渡是为了让它帮我们进行异常处理(PS:类似写程序为了正常运行加上try一个道理)
# -*- coding: utf-8 -*-
# @Time : 2022/11/10 15:13
# @Author : 红后
# @Email : [email protected]
# @blog : https://www.cnblogs.com/Red-Sun
# @File : coroutines.py
# @Software: PyCharm
import requests
def 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)
__EOF__
Recommend
-
11
深入Lua:在C代码中处理协程Yield在Lua和C的交互中,Lua经常调用C来完成一些性能敏感的操作,有时候C也会反过来回调Lua层的代码,比如table.sort这个API。假设我们要用C来实现一个foreach函数用于遍历table,并在遍...
-
8
php实现协程,真正的异步 | Lenix Bloggithub上php的协程大部分是根据这篇文章实现的:http://nikic.github.io/2012/12/22/Cooperative-multitasking-using-coroutines-in-PHP.html。 它们最终的结果都是把回调变成了优雅的顺序执行的代码,但还是阻塞的...
-
16
Python爬虫编程思想(26):Twisted的异步编程模型 ...
-
5
使用 algebraic effect 实现协程和异步IO2021-10-09最近的几篇博客都是关于 algebraic effect 的,主要是我发现这东西像发现宝了。它可以像 call/cc 一样强大,而又不至于太过失控。基于 algebraic effect 可以实现好多种其它的 f...
-
5
Python爬虫编程思想(88):抓取异步数据的原理_一个被知识诅咒的人-CSDN博客
-
5
Python爬虫编程思想(90):分析异步装载页面返回的json数据 ...
-
4
Python爬虫编程思想(106):基于Splash的爬虫--异步处理与go函数 ...
-
10
Home Menu...
-
10
钢铁知识库,一个学习python爬虫、数据分析的知识库。人生苦短,快用python。 之前我们使用requests库爬取某个站点的时候,每发出一个请求,程序必须等待网站返回响应才能接着运行,而在整个爬虫过程中,整个爬虫程序是一直在等待的,实际上没有做任何事情。
-
6
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK