第102天: Python异步之aiohttp

简介: 第102天: Python异步之aiohttp

什么是 aiohttp?一个异步的 HTTP 客户端\服务端框架,基于 asyncio 的异步模块。可用于实现异步爬虫,更快于 requests 的同步爬虫。


安装


pip install aiohttp


aiohttp 和 requests


requests 版爬虫


requests 同步方式连续 30 次简单爬取 http://httpbin.org 网站


import requestsfrom datetime import datetime
def fetch(url):    r = requests.get(url)    print(r.text)
start = datetime.now()
for i in range(30):    fetch('http://httpbin.org/get')
end = datetime.now()
print("requests版爬虫花费时间为:")print(end - start)


示例结果


# 打印网站返回的内容....requests版爬虫花费时间为:0:00:43.248761


从爬取结果可以看出,同步爬取 30 次网站将花费 43 秒左右的时间,耗时非常长。


aiohttp 版爬虫


使用 aiohttp 和 asyncio 异步方式简单爬取 30 次网站


import aiohttpimport asynciofrom datetime import datetime
async def fetch(client):    async with client.get('http://httpbin.org/get') as resp:        assert resp.status == 200        return await resp.text()
async def main():    async with aiohttp.ClientSession() as client:        html = await fetch(client)        print(html)
loop = asyncio.get_event_loop()
tasks = []for i in range(30):    task = loop.create_task(main())    tasks.append(task)
start = datetime.now()
loop.run_until_complete(main())
end = datetime.now()
print("aiohttp版爬虫花费时间为:")print(end - start)


示例结果


# 打印网站返回的内容....aiohttp版爬虫花费时间为:0:00:00.539416


从爬取时间可以看出,aiohttp 异步爬取网站只用了 0.5 秒左右的时间,比 requests 同步方式快了 80 倍左右,速度非常之快。


同一个 session


aiohttp.ClientSession() 中封装了一个 session 的连接池,并且在默认情况下支持 keepalives,官方建议在程序中使用单个 ClientSession 对象,而不是像上面示例中的那样每次连接都创建一个 ClientSession 对象,除非在程序中遇到大量的不同的服务。


将上面的示例修改为:


import aiohttpimport asynciofrom datetime import datetime
async def fetch(client):    print("打印 ClientSession 对象")    print(client)    async with client.get('http://httpbin.org/get') as resp:        assert resp.status == 200        return await resp.text()
async def main():    async with aiohttp.ClientSession() as client:       tasks = []       for i in range(30):           tasks.append(asyncio.create_task(fetch(client)))       await asyncio.wait(tasks)
loop = asyncio.get_event_loop()
start = datetime.now()
loop.run_until_complete(main())
end = datetime.now()print("aiohttp版爬虫花费时间为:")print(end - start)


示例结果


# 重复30遍打印 ClientSession 对象<aiohttp.client.ClientSession object at 0x1094aff98>aiohttp版爬虫花费时间为:0:00:01.778045


从上面爬取的时间可以看出单个 ClientSession 对象比多个 ClientSession 对象多花了 3 倍时间。ClientSession 对象一直是同一个 0x1094aff98。


返回值


Json 串


在上面的示例中使用 response.text() 函数返回爬取到的内容,aiohttp 在处理 Json 返回值的时候,可以直接将字符串转换为 Json。


async def fetch(client):    async with client.get('http://httpbin.org/get') as resp:        return await resp.json()

示例结果


{'args': {}, 'headers': {'Accept': '*/*', 'Accept-Encoding': 'gzip, deflate', 'Host': 'httpbin.org', 'User-Agent': 'Python/3.7 aiohttp/3.6.2'}, 'origin': '49.80.42.33, 49.80.42.33', 'url': 'https://httpbin.org/get'}


当返回的 Json 串不是一个标准的 Json 时,resp.json() 函数可以传递一个函数对 json 进行预处理,如:resp.json(replace(a, b)),replace()函数表示 a 替换为 b。


字节流


aiohttp 使用 response.read() 函数处理字节流,使用 with open() 方式保存文件或者图片


async def fetch(client):    async with client.get('http://httpbin.org/image/png') as resp:        return await resp.read()
async def main():    async with aiohttp.ClientSession() as client:        image = await fetch(client)        with open("/Users/xxx/Desktop/image.png", 'wb') as f:            f.write(image)


response.read() 函数可以传递数字参数用于读取多少个字节,如:response.read(3)读取前 3 个字节。


参数


aiohttp 可以使用 3 种方式在 URL 地址中传递参数


async def fetch(client):    params = [('a', 1), ('b', 2)]    async with client.get('http://httpbin.org/get',params=params) as resp:        return await resp.text()

示例 URL 地址


http://httpbin.org/get?a=1&b=2


async def fetch(client):    params = {"a": 1,"b": 2}    async with client.get('http://httpbin.org/get',params=params) as resp:        return await resp.text()

示例 URL 地址


http://httpbin.org/get?a=1&b=2


async def fetch(client):    async with client.get('http://httpbin.org/get',params='q=aiohttp+python&a=1') as resp:        return await resp.text()

示例 URL 地址


http://httpbin.org/get?q=aiohttp+python&a=1


请求头


aiohttp 在自定义请求头时,类似于向 URL 传递参数的方式


async def fetch(client):    headers = {'content-type': 'application/json', 'User-Agent': 'Python/3.7 aiohttp/3.7.2'}    async with client.get('http://httpbin.org/get',headers=headers) as resp:        return await resp.text()


COOKIES


cookies 是整个会话共用的,所以应该在初始化 ClientSession 对象时传递



async def fetch(client):    async with client.get('http://httpbin.org/get') as resp:        return await resp.text()
async def main():    cookies = {'cookies': 'this is cookies'}    async with aiohttp.ClientSession(cookies=cookies) as client:        html = await fetch(client)        print(html)


POST 方式


在前面的示例中都是以 GET 方式提交请求,下面用 POST 方式请求


async def fetch(client):    data = {'a': '1', 'b': '2'}    async with client.post('http://httpbin.org/post', data = data) as resp:        return await resp.text()


示例结果


{  "args": {},  "data": "",  "files": {},  "form": {    "a": "1",    "b": "2"  },  "headers": {    "Accept": "*/*",    "Accept-Encoding": "gzip, deflate",    "Content-Length": "7",    "Content-Type": "application/x-www-form-urlencoded",    "Host": "httpbin.org",    "User-Agent": "Python/3.7 aiohttp/3.6.2"  },  "json": null,  "origin": "49.80.42.33, 49.80.42.33",  "url": "https://httpbin.org/post"}
aiohttp版爬虫花费时间为:0:00:00.514402


在示例结果中可以看到 form 中的内容就是模拟 POST 方式提交的内容


超时


在请求网站时,有时会遇到超时问题,aiohttp 中使用 timeout 参数设置,单位为秒数,aiohttp 默认超时时间为 5 分钟


async def fetch(client):    async with client.get('http://httpbin.org/get', timeout=60) as resp:        return await resp.text()


总结


aiohttp 以异步的方式爬取网站耗时远小于 requests 同步方式,这里列举了一些 aiohttp 常用功能,希望对大家有所帮助。


代码地址

示例代码:https://github.com/JustDoPython/python-100-day/tree/master/day-102


系列文章


第101天:Python asyncio

从 0 学习 Python 0 - 100 大合集总结



目录
相关文章
|
2月前
|
搜索推荐 程序员 调度
精通Python异步编程:利用Asyncio与Aiohttp构建高效网络应用
【10月更文挑战第5天】随着互联网技术的快速发展,用户对于网络应用的响应速度和服务质量提出了越来越高的要求。为了构建能够处理高并发请求、提供快速响应时间的应用程序,开发者们需要掌握高效的编程技术和框架。在Python语言中,`asyncio` 和 `aiohttp` 是两个非常强大的库,它们可以帮助我们编写出既简洁又高效的异步网络应用。
160 1
|
1月前
|
Python
Python中的异步编程:使用asyncio和aiohttp实现高效网络请求
【10月更文挑战第34天】在Python的世界里,异步编程是提高效率的利器。本文将带你了解如何使用asyncio和aiohttp库来编写高效的网络请求代码。我们将通过一个简单的示例来展示如何利用这些工具来并发地处理多个网络请求,从而提高程序的整体性能。准备好让你的Python代码飞起来吧!
74 2
|
2月前
|
并行计算 数据处理 Python
Python并发编程迷雾:IO密集型为何偏爱异步?CPU密集型又该如何应对?
在Python的并发编程世界中,没有万能的解决方案,只有最适合特定场景的方法。希望本文能够为你拨开迷雾,找到那条通往高效并发编程的光明大道。
47 2
|
3月前
|
开发框架 并行计算 算法
揭秘Python并发神器:IO密集型与CPU密集型任务的异步革命,你竟还傻傻分不清?
揭秘Python并发神器:IO密集型与CPU密集型任务的异步革命,你竟还傻傻分不清?
51 4
|
18天前
|
数据采集 JSON 测试技术
Grequests,非常 Nice 的 Python 异步 HTTP 请求神器
在Python开发中,处理HTTP请求至关重要。`grequests`库基于`requests`,支持异步请求,通过`gevent`实现并发,提高性能。本文介绍了`grequests`的安装、基本与高级功能,如GET/POST请求、并发控制等,并探讨其在实际项目中的应用。
27 3
|
2月前
|
关系型数据库 MySQL 数据处理
探索Python中的异步编程:从asyncio到异步数据库操作
在这个快节奏的技术世界里,效率和性能是关键。本文将带你深入Python的异步编程世界,从基础的asyncio库开始,逐步探索到异步数据库操作的高级应用。我们将一起揭开异步编程的神秘面纱,探索它如何帮助我们提升应用程序的性能和响应速度。
|
2月前
|
调度 Python
深入理解 Python 中的异步操作 | python小知识
在现代编程中,异步操作是一个非常重要的概念,尤其是在处理 I/O 密集型任务时。使用异步操作可以显著提高程序的性能和响应速度。Python 提供了 `async` 和 `await` 关键字,使得编写异步代码变得更加直观和简洁【10月更文挑战第8天】
33 2
|
2月前
|
数据采集 前端开发 NoSQL
Python编程异步爬虫实战案例
Python编程异步爬虫实战案例
74 2
|
1月前
|
NoSQL 关系型数据库 MySQL
python协程+异步总结!
本文介绍了Python中的协程、asyncio模块以及异步编程的相关知识。首先解释了协程的概念和实现方法,包括greenlet、yield关键字、asyncio装饰器和async/await关键字。接着详细讲解了协程的意义和应用场景,如提高IO密集型任务的性能。文章还介绍了事件循环、Task对象、Future对象等核心概念,并提供了多个实战案例,包括异步Redis、MySQL操作、FastAPI框架和异步爬虫。最后提到了uvloop作为asyncio的高性能替代方案。通过这些内容,读者可以全面了解和掌握Python中的异步编程技术。
49 0
|
2月前
|
数据处理 Python
深入探索:Python中的并发编程新纪元——协程与异步函数解析
深入探索:Python中的并发编程新纪元——协程与异步函数解析
29 3
下一篇
DataWorks