第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 大合集总结



目录
相关文章
|
搜索推荐 程序员 调度
精通Python异步编程:利用Asyncio与Aiohttp构建高效网络应用
【10月更文挑战第5天】随着互联网技术的快速发展,用户对于网络应用的响应速度和服务质量提出了越来越高的要求。为了构建能够处理高并发请求、提供快速响应时间的应用程序,开发者们需要掌握高效的编程技术和框架。在Python语言中,`asyncio` 和 `aiohttp` 是两个非常强大的库,它们可以帮助我们编写出既简洁又高效的异步网络应用。
732 1
|
数据采集 存储 JSON
Python爬取知乎评论:多线程与异步爬虫的性能优化
Python爬取知乎评论:多线程与异步爬虫的性能优化
|
数据采集 存储 C++
Python异步爬虫(aiohttp)加速微信公众号图片下载
Python异步爬虫(aiohttp)加速微信公众号图片下载
|
Python
Python中的异步编程:使用asyncio和aiohttp实现高效网络请求
【10月更文挑战第34天】在Python的世界里,异步编程是提高效率的利器。本文将带你了解如何使用asyncio和aiohttp库来编写高效的网络请求代码。我们将通过一个简单的示例来展示如何利用这些工具来并发地处理多个网络请求,从而提高程序的整体性能。准备好让你的Python代码飞起来吧!
757 2
|
数据采集 监控 调度
干货分享“用 多线程 爬取数据”:单线程 + 协程的效率反超 3 倍,这才是 Python 异步的正确打开方式
在 Python 爬虫中,多线程因 GIL 和切换开销效率低下,而协程通过用户态调度实现高并发,大幅提升爬取效率。本文详解协程原理、实战对比多线程性能,并提供最佳实践,助你掌握异步爬虫核心技术。
|
人工智能 开发者 Python
Chainlit:一个开源的异步Python框架,快速构建生产级对话式 AI 应用
Chainlit 是一个开源的异步 Python 框架,帮助开发者在几分钟内构建可扩展的对话式 AI 或代理应用,支持多种工具和服务集成。
2311 9
|
Python
深入理解 Python 中的异步操作:async 和 await
Python 的异步编程通过 `async` 和 `await` 关键字处理 I/O 密集型任务,如网络请求和文件读写,显著提高性能。`async` 定义异步函数,返回 awaitable 对象;`await` 用于等待这些对象完成。本文介绍异步编程基础、`async` 和 `await` 的用法、常见模式(并发任务、异常处理、异步上下文管理器)及实战案例(如使用 aiohttp 进行异步网络请求),帮助你高效利用系统资源并提升程序性能。
1741 7
|
SQL 网络协议 安全
Python异步: 什么时候使用异步?
Asyncio 是 Python 中用于异步编程的库,适用于协程、非阻塞 I/O 和异步任务。使用 Asyncio 的原因包括:1) 使用协程实现轻量级并发;2) 采用异步编程范式提高效率;3) 实现非阻塞 I/O 提升 I/O 密集型应用性能。然而,Asyncio 并不适合所有场景,特别是在 CPU 密集型任务或已有线程/进程方案的情况下。选择 Asyncio 应基于项目需求和技术优势。
378 2
|
数据采集 JSON 测试技术
Grequests,非常 Nice 的 Python 异步 HTTP 请求神器
在Python开发中,处理HTTP请求至关重要。`grequests`库基于`requests`,支持异步请求,通过`gevent`实现并发,提高性能。本文介绍了`grequests`的安装、基本与高级功能,如GET/POST请求、并发控制等,并探讨其在实际项目中的应用。
452 3
|
关系型数据库 MySQL 数据处理
探索Python中的异步编程:从asyncio到异步数据库操作
在这个快节奏的技术世界里,效率和性能是关键。本文将带你深入Python的异步编程世界,从基础的asyncio库开始,逐步探索到异步数据库操作的高级应用。我们将一起揭开异步编程的神秘面纱,探索它如何帮助我们提升应用程序的性能和响应速度。

推荐镜像

更多