多任务异步协程,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任务中多线程/多进程还有存在的必要吗?

单线程多任务异步协程

单线程多任务异步抓取(asyncio)

爬虫04 /asyncioselenium规避检测动作链无头浏览器

asyncio创建协程解析