aiohttp 客戶端使用詳解


aiohttp分為服務器端和客戶端,本文只介紹客戶端。
由於上下文的緣故,請求代碼必須在一個異步的函數中進行:

async def fn():
pass
安裝
pip install aiohttp

 

基本語法

async with aiohttp.request('GET','https://github.com') as r:
await r.text()

 

指定編碼
await resp.text(encoding=‘windows-1251’)
適合讀取圖像等
await resp.read()

request案例
超時處理timeout
async with session.get('https://github.com', timeout=60) as r:

 

#使用示例, 進行一次請求

import aiohttp, asyncio

async def main():#aiohttp必須放在異步函數中使用
async with aiohttp.request('GET', 'https://api.github.com/events') as resp:
json = await resp.json()
print(json)

loop = asyncio.get_event_loop()
loop.run_until_complete(main())

 


------------------------------------------------------------------------------
#使用示例,進行多次請求

import aiohttp, asyncio

async def main():#aiohttp必須放在異步函數中使用
tasks = []
[tasks.append(fetch('https://api.github.com/events?a={}'.format(i))) for i in range(10)]#十次請求
await asyncio.wait(tasks)

async def fetch(url):
async with aiohttp.request('GET', url) as resp:
json = await resp.json()
print(json) 

loop = asyncio.get_event_loop()
loop.run_until_complete(main())
------------------------------------------------------------------------------

 


#使用示例,進行多次請求,並限制同時請求的數量

import aiohttp, asyncio

async def main(pool):#aiohttp必須放在異步函數中使用
tasks = []
sem = asyncio.Semaphore(pool)#限制同時請求的數量
[tasks.append(control_sem(sem, 'https://api.github.com/events?a={}'.format(i))) for i in range(10)]#十次請求
await asyncio.wait(tasks)

async def control_sem(sem, url):#限制信號量
async with sem:
await fetch(url)

async def fetch(url):
async with aiohttp.request('GET', url) as resp:
json = await resp.json()
print(json) 

loop = asyncio.get_event_loop()
loop.run_until_complete(main(pool=2))

 

上面的示例中可以正確的使用協程進行請求,但是由於aiohttp自身的原因會報 Unclosed client session 的警告。官方不推薦使用aiohttp.request的方式請求,可以將 aiohttp.request 換成 

aiohttp.ClientSession(**kw).request的方式即可

session
import aiohttp
async with aiohttp.ClientSession() as session:
async with session.get('https://api.github.com/events') as resp:
print(resp.status)
print(await resp.text())

 

我們創建了一個 ClientSession 對象命名為session,然后通過session的get方法得到一個 ClientResponse 對象,命名為resp,get方法中傳入了一個必須的參數url,就是要獲得源碼的http url。至此便通過協程完成了一個異步IO的get請求。
帶參數

session.post('http://httpbin.org/post', data=b'data')
session.put('http://httpbin.org/put', data=b'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=b'data')

 

不要為每次的連接都創建一次session,一般情況下只需要創建一個session,然后使用這個session執行所有的請求。

每個session對象,內部包含了一個連接池,並且將會保持連接和連接復用(默認開啟)可以加快整體的性能。

#使用示例

import aiohttp, asyncio

async def main(pool):#啟動
sem = asyncio.Semaphore(pool)
async with aiohttp.ClientSession() as session:#給所有的請求,創建同一個session
tasks = []
[tasks.append(control_sem(sem, 'https://api.github.com/events?a={}'.format(i), session)) for i in range(10)]#十次請求
await asyncio.wait(tasks)

async def control_sem(sem, url, session):#限制信號量
async with sem:
await fetch(url, session)

async def fetch(url, session):#開啟異步請求
async with session.get(url) as resp:
json = await resp.json()
print(json)

loop = asyncio.get_event_loop()
loop.run_until_complete(main(pool=2))

 

URL傳參數

params = {'key1': 'value1', 'key2': 'value2'}
# params = [('key', 'value1'), ('key', 'value2')]
async with session.get('http://httpbin.org/get',params=params) as resp:
assert resp.url =='http://httpbin.org/getkey2=value2&key1=value1'

 

請求頭

import json
url = 'https://api.github.com/some/endpoint'
payload = {'some': 'data'}
headers = {'content-type': 'application/json'}

await session.post(url,
data=json.dumps(payload),
headers=headers)

響應

assert resp.status == 200
resp.headers

await resp.text()
await resp.text(encoding=‘gb2312’)
await resp.read()
await resp.json()
await resp.content.read(10) #讀取前10個字節

 

文件保存

with open(filename, ‘wb’) as fd:
while True:
chunk = await resp.content.read(chunk_size)
if not chunk:
break
fd.write(chunk)

cookie
url = 'http://httpbin.org/cookies'
cookies = {'cookies_are': 'working'}
async with ClientSession(cookies=cookies) as session:
async with session.get(url) as resp:
assert await resp.json() == {
"cookies": {"cookies_are": "working"}}

 

POST
表單

payload = {'key1': 'value1', 'key2': 'value2'}
async with session.post('http://httpbin.org/post',
data=payload) as resp:
print(await resp.text())
json

import json
url = 'https://api.github.com/some/endpoint'
payload = {'some': 'data'}

async with session.post(url, data=json.dumps(payload)) as resp:
...

 

小文件

url = 'http://httpbin.org/post'
files = {'file': open('report.xls', 'rb')}
await session.post(url, data=files)

設置好文件名、content-type

url = 'http://httpbin.org/post'
data = FormData()
data.add_field('file',
open('report.xls', 'rb'),
filename='report.xls',
content_type='application/vnd.ms-excel')

await session.post(url, data=data)

 

大文件

keep-alive, 連接池,共享cookie
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)

 

同時連接數量
同時請求數量
conn = aiohttp.TCPConnector(limit=30)#同時最大進行連接的連接數為30,默認是100,limit=0的時候是無限制
同一端口連接數量
conn = aiohttp.TCPConnector(limit_per_host=30)#默認是0

 

自定義域名解析
自己指定域名解析

from aiohttp.resolver import AsyncResolver

resolver = AsyncResolver(nameservers=["8.8.8.8", "8.8.4.4"])
conn = aiohttp.TCPConnector(resolver=resolver)

 

代理
普通代理

async with aiohttp.ClientSession() as session:
async with session.get("http://python.org",
proxy="http://some.proxy.com") 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://some.proxy.com",
proxy_auth=proxy_auth) as resp:
print(resp.status)

 

或者

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM