【PY模块】aiohttp 使用

主要特点

  • 支持 异步客户端异步服务端
  • 支持开箱即用的 WebSocket 服务端WebSocket 客服端
  • 服务端还支持 中间件(Middlewares)和信号(Signals

初始

安装 pip install aiohttp

客户端

import asyncio
import aiohttp

async def main():
    async with aiohttp.ClientSession() as session:
        res = await session.get(url='https://bigdataboy.cn')
        print(res)

if __name__ == '__main__':
    loop = asyncio.get_event_loop()
    loop.run_until_complete(main())

mark

服务端

本文不会介绍

from aiohttp import web

async def handle(request):
    name = request.match_info.get('name', "bigdataboy")
    text = "Hello, " + name
    return web.Response(text=text)

app = web.Application()
app.add_routes([
    web.get('/', handle),
    web.get('/{name}', handle)]
)

if __name__ == '__main__':
    web.run_app(app=app, host='127.0.0.1', port=8080)

mark

快速上手

发出请求

import asyncio, aiohttp

async def main():
    async with aiohttp.ClientSession() as session: # 会话上下文
        async with session.get('http://httpbin.org/get') as resp: # 请求上下文
            print(resp.status)
            print(await resp.text())

asyncio.run(main())

其他请求方式

session.post('http://httpbin.org/post', data=b'data')
session.put('http://httpbin.org/put', data='data')
session.delete('http://httpbin.org/delete')
session.head('http://httpbin.org/get')
session.options('http://httpbin.org/get')
session.patch('http://httpbin.org/patch', data='data')

为了请求同一个网站更方便

async with aiohttp.ClientSession(base_url='http://httpbin.org') as session:
    async with session.get(url='/get') as resp:
        print(resp.status)  # 或 调用其他函数
    async with session.post(url='/post', data='data') as resp:
        print(resp.status)
    async with session.put(url='/put', data='data') as resp:
        print(resp.status)

提示 & 技巧

  • 一个站点的使用一个会话,==不要==为一个请求创建一个会话
  • 会话内部包含一个连接池。连接重用保持活动(默认情况下都打开)可以提高整体性能。
  • 不使用上下文形式

    需要收到关闭会话

session = aiohttp.ClientSession()
async with session.get('...'):
    # ...
await session.close()

参数传递

# GET
params = {'k': 'v'}
params = [('k', 'v'), ('k1', 'v1')]
async with session.get(url='/get', params=params) as resp:
    pass

# POST
data = 'str'
async with session.post(url='/post', data=data) as resp:
    pass

json = {'k': 'v'}
async with session.post(url='/post', json=json) as resp:
    pass

响应内容

async with session.get('https://bigdataboy.cn') as resp:
    # 状态码
    resp.status
    #文本解码
    await resp.text(encoding='utf-8') # 指定解码方式
    # json 解码
    await resp.json()
    # 二进制解码
    await resp.read()

流式响应内容

当响应文件过于庞大,使用read()json()text() 会把内容全部加载到内存,这是愚蠢的做法,应该使用流式响应。

async with session.get('https://api.github.com/events') as resp:
    with open('./xx', 'wb') as fd:
        chunk_size = 10
        async for chunk in resp.content.iter_chunked(chunk_size):
            fd.write(chunk)

网络套接字(WebSocket)

# 使用小蝌蚪聊天室测试
async with session.ws_connect('ws://kedou.workerman.net:8280/') as ws:
    async for msg in ws:
        print(msg)
        await ws.send_str('1122') # 发送数据
        # await ws.send_json()
        # await ws.send_json()

超时

# 单位 秒 默认超时 300 秒
timeout = aiohttp.ClientTimeout(total=60)
async with aiohttp.ClientSession(timeout=timeout) as session:
    ...
    # 会覆盖 session 设置的超时
    async with session.get(url, timeout=timeout) as resp:
        ...

自定义请求头

# 会话请求头
headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36'
}
async with aiohttp.ClientSession(headers=headers) as session:
    ...
    # 单独设置会 合并 会话请求头
    async with session.get(url='http://httpbin.org/headers', headers=headers) as resp:
        ...
url = 'http://httpbin.org/cookies'
cookies = {'cookies_are': 'working'}
async with aiohttp.ClientSession(cookies=cookies) as session:
    # 添加 Cookies 
    session.cookie_jar.update_cookies(cookies={'k1': 'v1'})
    # 单独设置会 合并到 会话Cookies
    async with session.get(url,cookies={'k': 'v'}) as resp:
        res = await resp.json()
        print(res)

mark

重定向

禁止重定向 allow_redirects=False

async with aiohttp.ClientSession() as session:
    async with session.get(url) as resp:
        print(resp.history)  # 重定向历史元祖
        print(resp.history[0])
        print(resp.history[0].url)

代理

aiohttp 还不能很好的支持 https代理

# HTTP 代理
async with aiohttp.ClientSession() as session:
    async with session.get(url=url,
                           proxy='http://127.0.0.1:7890') as resp:
        print(resp.status)

# 授权代理
async with aiohttp.ClientSession() as session:
    proxy_auth = aiohttp.BasicAuth('user', 'pass')
    async with session.get("http://python.org",
                           proxy="http://127.0.0.1:7890",
                           proxy_auth=proxy_auth) as resp:
        print(resp.status)

# socks 代理 pip install aiohttp_socks
from aiohttp_socks import ProxyConnector
conn = ProxyConnector.from_url('socks5://127.0.0.1:7890')
async with aiohttp.ClientSession(connector=conn, headers=headers) as session:
    ...

小技巧

推荐写法

import aiohttp
import asyncio

async def fetch(session, url):
    async with session.get(url) as response:
        return await response.text()

async def main():
    async with aiohttp.ClientSession() as session:
        # 此步
        html = await fetch(session, 'https://bigdataboy.cn')
        print(html)

loop = asyncio.get_event_loop()
loop.run_until_complete(main())
发表评论 / Comment

用心评论~