多任务异步协程,asyncio及aiohttp
Posted notebook3013
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了多任务异步协程,asyncio及aiohttp相关的知识,希望对你有一定的参考价值。
要实现异步协程,需要满足几个条件:
1,创建协程对象,且协程内部操作需要支持异步。
2,创建任务对象,如需为协程执行结果进行进一步处理,则需要为任务对象绑定回调函数。
3,创建事件循环,并将任务启动。
1 import asyncio 2 import requests 3 from lxml import etree 4 import aiohttp 5 import os 6 7 headers = 8 9 ‘User-Agent‘: ‘Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (Khtml, like Gecko) Chrome/75.0.3770.100 Safari/537.36‘ 10 11 12 13 # 普通单线程,同步执行任务 14 # url_ = ‘https://www.qiushibaike.com/pic/page//‘ 15 # for i in range(1, 100): 16 # url = url_.format(i) 17 # 18 # ret = requests.get(url=url, headers=headers).text 19 # tree = etree.HTML(ret) 20 # url_list = tree.xpath(‘//div[@id="content-left"]/div/div/a/img/@src‘) 21 # for url in url_list: 22 # name = url.split(‘/‘)[-1] 23 # print(name) 24 # img_url = ‘https:‘ + url 25 # img = requests.get(img_url, headers=headers).content 26 # with open(os.path.join(‘qiutu‘,name), ‘wb‘) as f: 27 # f.write(img) 28 29 # 使用async修饰过的函数,调用函数时,函数不执行,而是生成了一个协程对象 30 async def get_img(url): 31 """ 32 # aiohttp的细节处理: 33 # asnyc:硬性的语法要求关键字,应用aiohttp的代码模块 34 # await: 会出现阻塞的操作的代码中,需要用await修饰 35 36 """ 37 38 # ret = requests.get(url=url, headers=headers).text 39 name = url.split(‘/‘)[-1] 40 41 # 固定写法,aiohttp.ClientSession(),实例化一个异步请求对象 42 async with aiohttp.ClientSession() as aio: 43 # 用该对象向url发送异步请求 44 async with await aio.get(url=url, headers=headers) as ret: 45 # 将响应对象(图片)读取为二进制流,以便存储。(.text().json().read())对应requests的(.text.json.content) 46 res = await ret.read() 47 48 return name, res 49 50 51 # 定义一个回调函数(名字随意),回调函数接收该任务对象本身,(像self) 52 def callback(task): 53 # task.result()接收协程(特殊函数执行的返回结果,可进一步处理) 54 name, res = task.result() 55 # 将二进制流持久化成本地文件 56 with open(os.path.join(‘qiutu‘, name), ‘wb‘) as f: 57 f.write(res) 58 print(name, ‘下载完成‘) 59 60 61 # 通过糗图百科通用页面url,生成十页数据,并将十页数据中的所有图片链接存到urls中 62 urls = [] 63 url_ = ‘https://www.qiushibaike.com/pic/page//‘ 64 for i in range(1, 10): 65 page_url = url_.format(i) 66 ret = requests.get(url=page_url, headers=headers).text 67 # 通过xpath定位并获取糗图图片的src 68 tree = etree.HTML(ret) 69 url_list = tree.xpath(‘//div[@id="content-left"]/div/div/a/img/@src‘) 70 # 将每个图片的url存到urls中 71 for img_url in url_list: 72 urls.append(img_url) 73 print(img_url) 74 75 tasks = [] 76 77 for url in urls: 78 url = ‘https:‘ + url 79 # 执行协程对象函数(函数并不会真正去执行,而是生成一个协程对象) 80 cor = get_img(url) 81 # 将协程对象添加到asyncio.ensure_future中,生成一个任务对象 82 task = asyncio.ensure_future(cor) 83 # 为任务对象绑定添加一个回调函数,传入函数名 84 task.add_done_callback(callback) 85 # 将所有的任务对象添加到任务列表中 86 tasks.append(task) 87 88 # 创建一个事件循环对象 89 loop = asyncio.get_event_loop() 90 # 将任务列表加入事件循环,并开始执行 91 loop.run_until_complete(asyncio.wait(tasks))
注意!:
一个线程内最多大概可以注册500个协程。。任务数过多,需要多线程加异步协程实现。
以上是关于多任务异步协程,asyncio及aiohttp的主要内容,如果未能解决你的问题,请参考以下文章
Python有了asyncio和aiohttp在爬虫这类型IO任务中多线程/多进程还有存在的必要吗?