aiohttp官方教程翻译(2)—— 客户端编程之快速开始

Client Quickstart


1、Make a Request(制作一个请求)

首先导入库

import aiohttp
import asyncio

然后,让我们尝试获取一个网页页面。例如,访问 http://httpbin.org/get,运行以下代码,可以获得访问的数据:

import aiohttp
import asyncio

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())


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

现在,我们有了一个客户端时域称作session,有了一个客户端响应称作resp,我们可以从响应中得到我们想要的信息,ClientSession.get()协程的参数是这个HTTP url(即上面中的url)

为了使用HTTP的post请求,使用协程ClientSession.post():

session.post('http://httpbin.org/post', data=b'data')

其他的HTTP方法也是可以使用的:

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')

注意:
        请不要每个request都创建一个session,这是一个不好的习惯,应该一个session对应多个request。每一个session都包含一个连接,复用连接可以提高速度与效率。

一个session上下文管理器不是必须的,但是在下面这种情况下是需要的:

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

2、Passing Parameters In URLs(在URLs中传递参数)

例如,如果你想传递key1=value1和key2=value2到httpbin.org/get,你可以使用一个字典通过以下代码实现:

params = {'key1': 'value1', 'key2': 'value2'}
async def main():
    async with aiohttp.ClientSession() as session:
        async with session.get('http://httpbin.org/get',params=params) as resp:
            expect1 = 'http://httpbin.org/get?key2=value2&key1=value1'
            if str(resp.url) == expect1:
                print(1)
            else:
                print(0)
            expect2 = 'http://httpbin.org/get?key1=value1&key2=value2'
            if str(resp.url) == expect2:
                print(1)
            else:
                print(0)

也可以传递一个元组列表作为参数,代码如下:

params = [('key', 'value1'), ('key', 'value2')]
async def main():
    async with aiohttp.ClientSession() as session:
        async with session.get('http://httpbin.org/get',
                               params=params) as r:
            expect = 'http://httpbin.org/get?key=value1&key=value2'
            if str(r.url) == expect:
                print(1)
            else:
                print(0)

也可以使用一个字符串作为参数,代码如下:

async def main():
    async with aiohttp.ClientSession() as session:
        async with session.get('http://httpbin.org/get',
                               params='key=value+1') as r:
            if str(r.url) == 'http://httpbin.org/get?key=value+1':
                print(1)
            else:
            	print(0)

注意:
在aiohttp中,url请求前会自动进行url标准化,如果不需要标准化,可以设置以下格式(encoded=True):

await session.get(URL('http://example.com/%30', encoded=True))

警告:
parms与encoded参数不能同时设置


3、Response Content and Status Code(响应内容和状态代码 )

我们可以读取服务器的响应内容和其状态代码:

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

aiohttp会自动解码从服务器读得的数据,如果你想具体指定习惯的编码方式,可以采取以下代码:

await resp.text(encoding='windows-1251')

4、Binary Response Content(二进制响应内容)

你可以将响应主体设置为字节形式,以用作非文本请求:

print(await resp.read())

5、JSON Request(JSON请求)

任何session的请求方式如 request(), ClientSession.get(), ClientSesssion.post()等都接受json参数:

async with aiohttp.ClientSession() as session:
    async with session.post(url, json={'test': 'object'})

默认情况下session使用python的标准json模块来进行序列化,但是这里可以使用不同的序列化器,ClientSession()接受json序列化参数:

import ujson

async with aiohttp.ClientSession(
        json_serialize=ujson.dumps) as session:
    await session.post(url, json={'test': 'object'})

注意:ujson库比标准库json快但是略微互斥


6、JSON Response Content(JSON响应内容)

如果你要处理JSON数据,也有一个内嵌的JSON解码器供你使用:

async with session.get('https://api.github.com/events') as resp:
    print(await resp.json())

如果JSON解码失败,json()会提出一个例外,可以指定编码解码方式给json()

注意:以上方法会将全部响应数据读入内存,如果你计划读取大量数据,考虑使用下面的流响应方式


7、Streaming Response Content(流响应内容)

虽然 read(), json 和 text() 方法很方便,你需要小心使用他们,所有的这些方法都将全部响应数据读入内存。例如,如果你要下载几十亿字节的文件,这些方法会将数据全部导入内存空间。

除非,你使用了content属性,它是aiohttp.StreamReader类的实例化。gzip和deflate传输编码会自动为你解码:

async with session.get('https://api.github.com/events') as resp:
    await resp.content.read(10)

但是,一般来说,你应该使用这样的模式来保存流式传输到文件中的内容:

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

在从content显式读取数据后,不可以使用 read() , json() and text()


8、More complicated POST requests(更复杂的POST请求)

通常,当你想发送一些表单编码的数据——例如一个HTML表单。为了做到这点,只要传送一个字典给data参数,你的字典数据会自动被表单编码当请求发出时:

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

如果你想发送一个不是表单编码的数据,你可以传送一个字节类数据而不是字典:

async with session.post(url, data=b'\x00Binary-data\x00') as resp:
    ...

如果你想要发送JSON数据:

async with session.post(url, json={'example': 'test'}) as resp:
    ...

发送正确的文本类型,只需使用文本属性:

async with session.post(url, data='Тест') as resp:
    ...

9、POST a Multipart-Encoded File(POST一个多部分编码文件)

上传一个多部分编码文件:

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)

如果你传递了一个文件作为data参数,aiohttp会自动以流的方式上传到服务器


10、Streaming uploads(流式上传)

aiohttp支持多种流式上传,让你不用在上传大文件时将他们读入内存

简单来说,只需要提供一个类似文件的对象:

with open('massive-body', 'rb') as f:
   await session.post('http://httpbin.org/post', data=f)

或者你可以使用一个异步生成器:

async def file_sender(file_name=None):
    async with aiofiles.open(file_name, 'rb') as f:
        chunk = await f.read(64*1024)
        while chunk:
            yield chunk
            chunk = await f.read(64*1024)

# Then you can use file_sender as a data provider:

async with session.post('http://httpbin.org/post',
                    data=file_sender(file_name='huge_file')) as resp:
    print(await resp.text())

因为content属性是StreamReader(提供异步迭代器协议),所以可以将get和post请求链接在一起:

resp = await session.get('http://python.org')
await session.post('http://httpbin.org/post',
                   data=resp.content)

11、WebSockets(Web套接字)

你需要使用 aiohttp.ClientSession.ws_connect() 协程去完成客户端WebSocket连接,它接受一个url作为第一个参数并返回ClientWebSocketResponse,通过此对象你可以使用响应方法和websocket交流:

async with session.ws_connect('http://example.org/ws') as ws:
    async for msg in ws:
        if msg.type == aiohttp.WSMsgType.TEXT:
            if msg.data == 'close cmd':
                await ws.close()
                break
            else:
                await ws.send_str(msg.data + '/answer')
        elif msg.type == aiohttp.WSMsgType.ERROR:
            break
12、Timeouts(超时暂停)

超时暂停设置在ClientTimeout这个数据结构中

默认情况下aiohttp使用一个5分钟的超时暂停,这意味着所有操作都必须在五分钟内完成

可以通过超时参数覆盖此值:

timeout = aiohttp.ClientTimeout(total=60)
async with aiohttp.ClientSession(timeout=timeout) as session:
    ...

也可以在一个请求中覆盖此值:

async with session.get(url, timeout=timeout) as resp:
    ...

支持的ClientTimeout字段有:
total:

   全部的操作时间,包括连接完成,发送请求和读取响应

connect:

   时间包括有为新连接建立连接,或者超过池连接限制时
   等待空闲连接

sock_connect:

   超时暂停设置给对等网络的新连接,而不是从池中

sock_read:

   从对等机读取新的数据之间运行的最大超时时间

更多详细请参考 ClientTimeout

默认设置为:

aiohttp.ClientTimeout(total=5*60, connect=None,
                      sock_connect=None, sock_read=None)

finished

你可能感兴趣的:(aiohttp)