专栏首页python编程军火库大型fastapi项目实战 高并发请求神器之aiohttp(上) [建议收藏]

大型fastapi项目实战 高并发请求神器之aiohttp(上) [建议收藏]

大型fastapi项目实战 高并发请求神器之aiohttp(上) [建议收藏]

  • aiohttp介绍及安装
    • 1.背景介绍
    • 2.aiohttp 是什么
    • 3.aiohttp 核心功能
    • 4.aiohttp 库安装
  • aoihttp 业务核心功能
    • 1. 发起 get 请求
    • 2. 发起 post 请求
    • 3. 向 url 中传递参数
    • 4. 向目标服务器上传文件
    • 5. 设置请求超时
  • aoihttp 爬虫核心功能
    • 1. 自定义cookie
    • 2. 在多个请求之间共享cookie
    • 3. 自定义请求头
    • 4. SSL验证警告问题
    • 5. 代理问题
  • aoihttp 连接池
    • 1.使用连接器
    • 2.限制连接池的容量
  • 小结:

大型fastapi项目实战 高并发请求神器之aiohttp(上) [建议收藏]

aiohttp介绍及安装

1.背景介绍

在 Python 众多的 HTTP 客户端中,最有名的莫过于 requests、aiohttp 和 httpx。在不借助其他第三方库的情况下,requests 只能发送同步请求;aiohttp 只能发送异步请求;httpx 既能发送同步请求,又能发送异步请求。在并发量大的情况下,如何高效的处理数据,异步是我们的优选,今天我们主要详解的是在生产环境广泛使用的 aiohttp。

2.aiohttp 是什么

aiohttp 是一个为 Python 提供异步HTTP 客户端/服务端编程,基于 asyncio(Python用于支持异步编程的标准库)的异步库。

3.aiohttp 核心功能
  1. 同时支持客户端使用和服务端使用。
  2. 同时支持服务端 WebSockets 组件和客户端 WebSockets 组件,开箱即用。
  3. web 服务器具有中间件,信号组件和可插拔路由的功能。 以下的案例都是基于客户端展开,我们在生产中主要是用 aiohttp 来做客户端用。
4.aiohttp 库安装
  1. $ pip install aiohttp
  2. 对于更快的客户端 API DNS 解析方案,aiodns 是个很好的选择,极力推荐,$ pip install aiodns

aoihttp 业务核心功能

1. 发起 get 请求
# -*- encoding: utf-8 -*-

import asyncio
import aiohttp


async def main():
    async with aiohttp.ClientSession() as session:
        async with session.get('http://www.baidu.com') as resp:
            print(resp.status)
            res = await resp.text()
            print(res[:100])


if __name__ == '__main__':
    # 注意:
    # python3.7+ 支持写法
    # asyncio.run(main())
    # python3.6及以下版本写法
    event_loop = asyncio.get_event_loop()
    result = event_loop.run_until_complete(asyncio.gather(main()))
    event_loop.close()
2. 发起 post 请求
# -*- encoding: utf-8 -*-
import asyncio
import aiohttp


async def post_v1():
    data = b'\x00Binary-data\x00'  # 未经编码的数据通过bytes数据上传
    data = 'text'  # 传递文本数据
    data = {'key': 'value'}  # 传递form表单
    async with aiohttp.ClientSession() as sess:
        async with sess.post('http://httpbin.org/post', data=data) as resp:
            print(resp.status)


# 复杂的 post 请求
async def post_v2():
    payload = {'key': 'value'}  # 传递 pyload
    async with aiohttp.ClientSession() as sess:
        async with sess.post('http://httpbin.org/post', json=payload) as resp:
            print(resp.status)


if __name__ == '__main__':
    event_loop = asyncio.get_event_loop()
    result = event_loop.run_until_complete(asyncio.gather(main()))
    event_loop.close()
3. 向 url 中传递参数

有些场景是需要拼接请求url 在这个时候可以使用本 case 来做处理

# -*- encoding: utf-8 -*-
import asyncio
import aiohttp


async def main():
    """ 以下三种方式均可以 """
    params = {'key1': 'value1', 'key2': 'value2'}
    params = [('key', 'value1'), ('key', 'value2')]
    params = 'key=value+1'
    async with aiohttp.ClientSession() as sess:
        async with sess.get('http://httpbin.org/get', params=params) as resp:
            print(resp.status)


if __name__ == '__main__':
    event_loop = asyncio.get_event_loop()
    result = event_loop.run_until_complete(asyncio.gather(main()))
    event_loop.close()
4. 向目标服务器上传文件

有时候,我们确实是有想服务器传文件的需求,eg:上传回执单;上传图片...... 100张 10000张的量级的时候我们会想用多线程去处理,但量再大 你再使用 多线程+requests 的方式就会发现有大量的报错,若有类似的使用场景,可以用以下 case 处理

import aiohttp


async def main():
    """ 传递文件 """
    files = {'file': open('report.xls', 'rb')}
    async with aiohttp.ClientSession() as sess:
        async with sess.post('http://httpbin.org/post', data=files) as resp:
            print(resp.status)
            print(await resp.text())


async def main2():
    """ 实例化 FormData 可以指定 filename 和 content_type """
    data = aiohttp.FormData()
    data.add_field('file',
                   open('report.xls', 'rb'),
                   filename='report.xls',
                   content_type='application/vnd.ms-excel')
    async with aiohttp.ClientSession() as sess:
        async with sess.post('http://httpbin.org/post', data=data) as resp:
            print(resp.status)
            print(await resp.text())


async def main3():
    """ 流式上传文件 """
    async with aiohttp.ClientSession() as sess:
        with open('report.xls', 'rb') as f:
            async with sess.post('http://httpbin.org/post', data=f) as resp:
                print(resp.status)
                print(await resp.text())


async def main4():
    """ 因为 content属性是 StreamReader(提供异步迭代器协议),
    所以可以将 get 和 post 请求链接在一起。python3.6+能使用"""
    async with aiohttp.ClientSession() as sess:
        async with sess.get('http://python.org') as resp:
            async with sess.post('http://httpbin.org/post', data=resp.content) as r:
                print(r.status)
                print(await r.text())
5. 设置请求超时

有时候,我们向服务器发送请求,若没有设置超时时间,此请求就会一直阻塞直到系统报错,这对于我们的系统是无法容忍的,所以发请求的时候千万要记得加上超时时间。

import aiohttp

timeout = aiohttp.ClientTimeout(total=60)


async def main():
    async with aiohttp.ClientSession(timeout=timeout) as sess:
        async with sess.get('http://httpbin.org/get') as resp:
            print(resp.status)
            print(await resp.text())

aoihttp 爬虫核心功能

1. 自定义cookie
import aiohttp
import asyncio


cookies = {'cookies_are': 'working'}

async def main():
    async with aiohttp.ClientSession(cookies=cookies) as session:
        async with session.get('http://httpbin.org/cookies') as resp:
            print(resp.status)
            print(await resp.text())
            assert await resp.json() == {"cookies": {"cookies_are": "working"}}

if __name__ == "__main__":
    event_loop = asyncio.get_event_loop()
    result = event_loop.run_until_complete(asyncio.gather(main()))
    event_loop.close()
2. 在多个请求之间共享cookie
import aiohttp
import asyncio


async def main():
    async with aiohttp.ClientSession() as session:
        await session.get('http://httpbin.org/cookies/set?my_cookie=my_value')
        filtered = session.cookie_jar.filter_cookies('http://httpbin.org')
        print(filtered)
        assert filtered['my_cookie'].value == 'my_value'
        async with session.get('http://httpbin.org/cookies') as r:
            json_body = await r.json()
            print(json_body)
            assert json_body['cookies']['my_cookie'] == 'my_value'


if __name__ == "__main__":
    event_loop = asyncio.get_event_loop()
    result = event_loop.run_until_complete(asyncio.gather(main()))
    event_loop.close()

Cookie 的安全性问题: 默认 ClientSession 使用的是严格模式的 aiohttp.CookieJar. RFC 2109,明确的禁止接受url和ip地址产生的 cookie,只能接受 DNS 解析IP产生的cookie。

可以通过设置 aiohttp.CookieJar 的 unsafe=True 来配置

jar = aiohttp.CookieJar(unsafe=True)
session = aiohttp.ClientSession(cookie_jar=jar)

使用虚假Cookie Jar: 有时不想处理cookie。这时可以在会话中使用aiohttp.DummyCookieJar来达到目的。

jar = aiohttp.DummyCookieJar()
session = aiohttp.ClientSession(cookie_jar=jar)
3. 自定义请求头
import aiohttp
import asyncio


async with aiohttp.ClientSession(headers={'User-Agent': 'your agent'
"refer":"http://httpbin.org"}) as session:
    async with session.get('http://httpbin.org/headers') as resp:
        print(resp.status)
        print(await resp.text())
4. SSL验证警告问题

默认情况下,aiohttp对HTTPS协议使用严格检查,如果你不想上传SSL证书,可将ssl设置为False。

r = await session.get('https://example.com', ssl=False)
5. 代理问题
# 第一种
async with aiohttp.ClientSession() as session:
    proxy_auth = aiohttp.BasicAuth('user', 'pass')
    async with session.get("http://python.org", proxy="http://proxy.com", proxy_auth=proxy_auth) as resp:
        print(resp.status)

# 第二种
session.get("http://python.org", proxy="http://user:pass@some.proxy.com")

aoihttp 连接池

1.使用连接器

想要调整请求的传输层你可以为ClientSession及其同类组件传递自定义的连接器。例如:

conn = aiohttp.TCPConnector()
session = aiohttp.ClientSession(connector=conn)

注:不要给多个会话对象使用同一个连接器,某一会话对象拥有其所有权。

2.限制连接池的容量

限制同一时间打开的连接数可以传递limit参数:

conn = aiohttp.TCPConnector(limit=30)

这样就将总数限制在30,默认情况下是100.如果你不想有限制,传递0即可:

conn = aiohttp.TCPConnector(limit=0)

小结:

爬虫常用的功能单独来写,主要是 aiohttp 还有一个问题没有解决,通过阅读源码确实是无法很好解决这个问题,在网上搜索了大半天基本没有有效的解决方案,so 笔者会给出一个自己找到的解决方案,在接下来的文章中我会进行分享。

文章分享自微信公众号:
python编程军火库

本文参与 腾讯云自媒体分享计划 ,欢迎热爱写作的你一起参与!

作者:还是牛
原始发表时间:2021-01-31
如有侵权,请联系 cloudcommunity@tencent.com 删除。
登录 后参与评论
0 条评论

相关文章

  • 大型fastapi项目实战 高并发请求神器之aiohttp(下)

    1.先通过 event_loop = asyncio.get_event_loop() 创建了一个事件循环 2.通过 asyncio.gather 接受多个 f...

    python编程从入门到实践
  • python大型项目后台异步这一篇就够了

    点击python编程从入门到实践,置顶 公众号重磅 python入门资料,第一时间送达

    python编程从入门到实践
  • 国人开源的异步 Python ORM:GINO

    https://python-gino.org/docs/zh/master/tutorials/announcement.html

    Python猫
  • 怒肝半月!Python 学习路线+资源大汇总

    视频地址:https://www.bilibili.com/video/BV133411C7u5/

    程序员鱼皮
  • 用了2周,终于把Python网站开发库大全整理完了

    用了 2 周的时间整理了 Python 中所有的网站开发库(下文简称:Web 框架),供大家学习参考。

    Python小二
  • python协程初体验

    在了解了Python并发编程的多线程和多进程之后,我们来了解一下基于asyncio的异步IO编程 => 协程

    测试加
  • 关于Python爬虫,这里有一条高效的学习路径

    如果你仔细观察,就不难发现,懂爬虫、学习爬虫的人越来越多,一方面,互联网可以获取的数据越来越多,另一方面,像 Python这样的编程语言提供越来越多的优秀工具,...

    Python进阶者
  • 整理了 37 个 Python 网站开发库

    用了 2 周的时间整理了 Python 中所有的网站开发库(下文简称:Web 框架),供大家学习参考。

    Python研究者
  • 人类高质量 Java 学习路线【一条龙版】

    大家好,我是鱼皮。现在网上的编程资料实在太多了,而且人人肯定都说自己的最好,那就导致大家又不知道怎么选了。大部分的博主推荐资源,也就是把播放量高的视频说一遍,水...

    程序员鱼皮
  • 无限容量数据库架构设计

    花了不少时间,把自己曾经做过的系统,曾经遇到到的问题,曾经实践过的架构方案,梳理总结和沉淀,尽量“系统的”记录成文字,和大家一起讨论。

    Java知音
  • 关于Python爬虫,这里有一条高效的学习路径

    关键字全网搜索最新排名 【机器学习算法】:排名第一 【机器学习】:排名第一 【Python】:排名第三 【算法】:排名第四 ? 如果你仔细观察,就不难发现,懂爬...

    昱良
  • Python爬虫 | 一条高效的学习路径

    数据是创造和决策的原材料,高质量的数据都价值不菲。而利用爬虫,我们可以获取大量的价值数据,经分析可以发挥巨大的价值,比如:

    conanma
  • 同步与异步 Python 有何不同?

    你是否听人们说过,异步 Python 代码比“普通(或同步)Python 代码更快?果真是那样吗?

    Python猫
  • 2019 年 10 大顶级 Python 支持库

    原文链接: https://tryolabs.com/blog/2019/12/10/top-10-python-libraries-of-2019/

    龙哥
  • 【腾讯云开发者社区年度征文】2020征文活动获奖名单公布

    由腾讯云+社区主办的云+社区 2020 年度征文活动在2020年12月31号圆满的落下帷幕。年度征文活动自2020年11月发布后,吸引了众多社区内的小伙伴。经过...

    腾讯云开发者社区
  • GitHub上最火的7个spring cloud开源项目,对新手太友好了

    微服务架构(Microservice Architecture)是一种架构概念,旨在通过将功能分解到各个离散的服务中以实现对解决方案的解耦。你可以将其看作是在架...

    北游
  • django、flask和tornado区别

    在python的web开发框架中,目前使用量最高的几个是django、flask和tornado, 经常会有人拿这几个对比,相信大家的初步印象应该是 djang...

    Python之道

扫码关注腾讯云开发者

领取腾讯云代金券