aiohttp简介与简单使用

简介

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

核心功能

  • 同时支持客户端使用和服务端使用
  • 同时支持服务端WebSockets组件和客户端WebSockets组件
  • web服务器具有中间件、信号组件和可插拨路由的功能

安装

安装命令如下(推荐使用python3.7或以上版本)

pip3 install aiohttp

如果你想把chardetaiodnsbrotlipy一同安装的话,可以使用以下命令安装

pip3 install aiohttp[speedups]

快速开始

客户端使用

简单发送一个http请求

import aiohttp
import asyncio


async def main():
    async with aiohttp.ClientSession() as session:
        async with session.get('http://python.org') as response:
            print('Status:', response.status)
            print('Content-type:', response.headers['content-type'])

            html = await response.text()
            print(f'Body: {html[:15]}...')


if __name__ == '__main__':
    asyncio.run(main())

结果如下

Status: 200
Content-type: text/html; charset=utf-8
Body: <!doctype html>...

服务端使用

简单搭建一个web服务

from aiohttp import web


# 视图函数
async def hello(request):
    name = request.match_info.get('name', 'Python')
    text = f'Hello, {name}'
    return web.Response(text=text)


app = web.Application()
app.add_routes([
    web.get('/', hello),
    web.get('/{name}', hello)
])  # 添加路由

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

一个简单的服务就成功搭建了,在浏览器*问http://127.0.0.1:8080或者http://127.0.0.1:8080/name(name为你输入的字符串)就可以看到对应的返回信息。

aiohttp客户端的简单应用

基本API的使用

aiohttp提供了一个简单发送HTTP请求的协程方法:aiohttp.request()

基本API对于不需要持久连接,cookies和复杂的连接附件(如SSL证书)的HTTP请求来说是比较好用的,它的用法和python网络请求requests包的用法差不多。

import aiohttp
import asyncio


async def get_html():
    async with aiohttp.request('GET', 'http://python.org/') as resp:
        print(resp.status)
        print(await resp.text())


if __name__ == '__main__':
    asyncio.run(get_html())

以上例子,aiohttp.request()中的第一个参数为method(HTTP方法),第二个参数为url(请求链接),其他比较重要的关键字参数还有headers(请求头信息)、cookies(请求时携带的cookies)、params(原url组合的参数)、data(请求体的参数)等。

客户端会话

客户端会话(Client Session)是比较推荐使用的发起HTTP请求的接口。

会话(Session)封装有一个连接池(连接池实例),默认支持持久连接。除非需要连接非常多不同的服务器,否则还是建议你在应用程序中只使用一个会话(Session),这样有利于连接池。

import aiohttp
import asyncio


async def get_html(session, url):
    # 发送一个GET请求获取页面信息
    async with session.get(url) as resp:
        print(f'--- current url is {url} ---')
        print('Status:', resp.status)
        return await resp.text()


async def main():
    # 建立一个客户端会话
    async with aiohttp.ClientSession() as session:
        html1 = await get_html(session, 'http://python.org')
        html2 = await get_html(session, 'https://baidu.com')
        print(html1)
        print(html2)


if __name__ == '__main__':
    asyncio.run(main())

通过aiohttp.ClientSession()创建一个客户端会话session,session可以使用get和post等请求方法发送请求,相关参数也是类似requests包的传参。

aiohttp异步爬虫

我们来使用aiohttp实现一个简单的爬虫,爬取三张图片

import time
import aiohttp
import asyncio


async def get_html(session, url):
    print('发送请求:', url)
    async with session.get(url) as response:
        content = await response.content.read()
        print('得到结果', url, len(content))
        filename = url.rsplit('/')[-1]
        print(f'正在下载{filename}...')
        with open(filename, 'wb') as file_object:
            file_object.write(content)
            print(f'{filename}下载成功')


async def main():
    async with aiohttp.ClientSession() as session:
        start_time = time.time()
        url_list = [
            'https://images.cnblogs.com/cnblogs_com/blueberry-mint/1877253/o_201106093544wallpaper1.jpg',
            'https://images.cnblogs.com/cnblogs_com/blueberry-mint/1877253/o_201106093557wallpaper2.jpg',
            'https://images.cnblogs.com/cnblogs_com/blueberry-mint/1877253/o_201106093613wallpaper3.jpg',
        ]
        tasks = [asyncio.create_task(get_html(session, url)) for url in url_list]
        await asyncio.wait(tasks)
        end_time = time.time()
        print(f'it cost {round(end_time - start_time, 4)}s.')


if __name__ == '__main__':
    asyncio.run(main())

执行结果如下

发送请求: https://images.cnblogs.com/cnblogs_com/blueberry-mint/1877253/o_201106093544wallpaper1.jpg
发送请求: https://images.cnblogs.com/cnblogs_com/blueberry-mint/1877253/o_201106093557wallpaper2.jpg
发送请求: https://images.cnblogs.com/cnblogs_com/blueberry-mint/1877253/o_201106093613wallpaper3.jpg
得到结果 https://images.cnblogs.com/cnblogs_com/blueberry-mint/1877253/o_201106093613wallpaper3.jpg 1215029
正在下载o_201106093613wallpaper3.jpg...
o_201106093613wallpaper3.jpg下载成功
得到结果 https://images.cnblogs.com/cnblogs_com/blueberry-mint/1877253/o_201106093544wallpaper1.jpg 1326652
正在下载o_201106093544wallpaper1.jpg...
o_201106093544wallpaper1.jpg下载成功
得到结果 https://images.cnblogs.com/cnblogs_com/blueberry-mint/1877253/o_201106093557wallpaper2.jpg 1867449
正在下载o_201106093557wallpaper2.jpg...
o_201106093557wallpaper2.jpg下载成功
it cost 0.1745s.

本例子中先创建一个客户端会话session,在session使用asyncio.create_task()创建3个协程任务,然后通过asyncio.wait()挂起任务(异步执行)并获取最终结果。

上一篇:Codeforces Round #665 Div. 2 A-D题题解


下一篇:如何让你写的爬虫速度像坐火箭一样快【并发请求】