13、爬虫-协程-asyncio和异步操作-aiohttp
概念:当程序sleep或者input、output等待的时候、cpu是处于堵塞状态的、cpu此时是不再为我们的代码服务的、所以协程就是当遇到了前面这种情况的时候可以选择性的切换到其他任务上
同步协程:asyncio
当程序在睡眠的时候注意加上:
await asyncio.sleep(2)
"""
多任务协程asyncio
"""
import asyncio
import time
async def func1():
print("异步1")
#time.sleep(2) #同步操作、当程序出现了同步操作的时候、异步就中断了
await asyncio.sleep(2) #异步操作代码 \ await 表示挂起2s、将程序切换到执行其它代码
print("异步1")
async def func2():
print("异步2")
#time.sleep(2)
await asyncio.sleep(2)
print("异步2")
async def func3():
print("异步3")
#time.sleep(2)
await asyncio.sleep(2)
print("异步3")
#异步协程函数
async def main():
# #第一种写法(不推荐)
# f1 = func1()
# await f1 #一般await挂起操作放在协程对象前面
#第二种写法(推荐)
tasks = [
#在python11后需要将协程对象包含在 asyncio.create_task()里面
asyncio.create_task(func1()),
asyncio.create_task(func2()),
asyncio.create_task(func3())
#python8之前可以这样写
# func1(),
# func2(),
# func3()
]
await asyncio.wait(tasks)
if __name__ == '__main__':
time1 = time.time()
#一次启动多个任务(协程)
asyncio.run(main())
time2 = time.time()
print(time2 - time1) #异步协程执行三个函数只需2秒
异步操作:aiohttp
案例:使用异步协程下载多个图片
"""
异步操作
aiohttp
pip install aiohttp
requests.get() 是一个同步的请求、需要将其换为异步请求
"""
import asyncio
import aiohttp #pip install aiohttp
#案例下载三张图片
urls = [
"https://www.keaitupian.cn/cjpic/frombd/2/253/2164177160/3074906821.jpg",
"https://www.keaitupian.cn/cjpic/frombd/2/253/3564686522/2864443333.jpg",
"https://www.keaitupian.cn/cjpic/frombd/1/253/351679977/2120764836.jpg"
]
async def aiodownload(url):
#截取urls的最后的一串最为图片名
pic_name = url.rsplit("/", 1)[1] #从右边开始切,切一次、得到[1]的位置内容
#这里的aiohttp.ClientSession() 表示创建会话 相当于 requests.get() 或 requests.post()对象一样
#request = aiohttp.ClientSession()
#注意这里的with .... as ..:与打开文件的方式一样、打开连接后会自动关闭.close连接
async with aiohttp.ClientSession() as session: #获取会话
async with session.get(url) as response: #请求url 连接(相当于requests.get())
# response.text() #读文本
# response.content() #读二进制文本内容
# response.json() #读json内容
#将请求到的内容写入到文件中
with open(pic_name ,"wb") as file:
file.write(await response.content.read()) #这里读取的内容是异步的、所以需要await挂起
print(pic_name,"done")
#发送图片请求
#得到图片内容
#保存到文件
async def main():
tasks = []
for url in urls:
tasks.append(aiodownload(url))
await asyncio.wait(tasks)
if __name__ == '__main__':
#asyncio.run(main()) #使用这个去循环会报错RuntimeError: Event loop is closed、替换为下面的即可
loop = asyncio.get_event_loop() #创建新的事件循环
loop.run_until_complete(main()) #使用新的事件循环去只需异步任务