1. 程式人生 > 實用技巧 >aiohttp簡介與簡單使用

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()掛起任務(非同步執行)並獲取最終結果。