客户端使用

发起请求

让我们从导入aiohttp模块开始:

import aiohttp

好啦,我们来尝试获取一个web页面。比如我们来获取下GitHub的时间轴。

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

我们现在有了一个会话(session)对象,由ClientSession对象赋值而来,还有一个变量resp,它其实是ClientResponse对象。我们可以从这个响应对象中获取我们任何想要的信息。协程方法ClientSession.get()的主要参数接受一个HTTP 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')

注意:

不要为每个请求都创建一个会话。大多数情况下每个应用程序只需要一个会话就可以执行所有的请求。 每个会话对象都包含一个连接池,可复用的连接和持久连接状态(keep-alives,这两个是默认的)可提升总体的执行效率。

发起JSON请求:

每个会话的请求方法都可接受json参数。

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

默认情况下会话(session)使用Python标准库里的json模块解析json信息。但还可使用其他的json解析器。可以给ClientSession指定json_serialize参数来实现:

import ujson

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

传递URL中的参数:

你可能经常想在URL中发送一系列的查询信息。如果你手动构建他们,这些信息会以键值对的形式出现在?后面,比如: httpbin.org/get?key=val。请求对象允许你使用dict(字典,python中的数据类型)发送它们,使用params参数即可。例如: 如果你要把 key1=value1,key2=value2放到httpbin.org/get后面,你可以用下面的方式:

params = {'key1': 'value1', 'key2': 'value2'}
async with session.get('http://httpbin.org/get',
params=params) as resp:
assert str(resp.url) == 'http://httpbin.org/get?key2=value2&key1=value1'

看,URL已经被正确的编码啦。 同键不同值的并联字典(MultiDict) 也同样支持。 可使用带有两个tuples(元组,python中的数据类型)的list(列表,python中的数据类型)来构建:

params = [('key', 'value1'), ('key', 'value2')]
async with session.get('http://httpbin.org/get',
params=params) as r:
assert str(r.url) == 'http://httpbin.org/get?key=value2&key=value1'

同样也允许你传递str(字符串)给params,但要小心一些不能被编码的字符。就是一个不能被编码的字符:

async with session.get('http://httpbin.org/get',
params='key=value+1') as r:
assert str(r.url) == 'http://httpbin.org/get?key=value+1'

注意:

aiohttp会在发送请求前标准化URL。 域名部分会用IDNA 编码,路径和查询条件会重新编译(requoting)。 比如:URL('http://example.com/путь%30?a=%31')会被转化为URL('http://example.com/%D0%BF%D1%83%D1%82%D1%8C/0?a=1') 如果服务器需要接受准确的表示并不要求编译URL,那标准化过程应是禁止的。 禁止标准化可以使用encoded=True:

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

警告:

传递params时不要用encode=True,这俩参数不能同时使用。

获取响应内容

我们可以读取服务器的响应内容。想想我们获取GitHub时间轴的例子:

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

这样会打印出类似于下面的信息:

'[{"created_at":"2015-06-12T14:06:22Z","public":true,"actor":{...

aiohttp将会自动解码内容。你可以为text()方法指定编码(使用encoding参数):

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

获取二进制响应内容

你也可以以字节形式获取响应,这样得到的就不是文本了:

print(await resp.read())
b'[{"created_at":"2015-06-12T14:06:22Z","public":true,"actor":{...

gzipdefalte传输编码会自动解码。 你也可以使其支持brotli传输编码的解码,只需安装brotlipy即可。

获取JSON响应内容

以防你需要处理JSON数据,内置了一个JSON解码器:

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

如果JSON解码失败,json()方法将会抛出一个异常。你还可以在调用json()时指定编码器和解码器函数。

注意:

这些方法会读出内存中所有响应的内容。如果你要读非常多的数据,考虑使用流式响应方法进行读取。请看之后的文档。

获取流式响应内容

read(), json(), text()等方法使用起来很方便,但也要注意谨慎地使用。上述方法会将所有的响应内容加载到内存。举个例子,如果你要下载几个G的文件,这些方法还是会将所有内容都加载到内存,内存会表示"臣妾做不到啊~"(如果内存不够的话)。作为代替你可以用content属性。content其实是 aiohttp.StreamReader类的实例。gzipdeflate传输编码同样会自动解码。

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(), text()了。

获取请求信息

ClientResponse(客户端响应)对象含有request_info(请求信息),主要是urlheaders信息。 raise_for_status结构体上的信息会被复制给ClientResponseError实例。

自定义Headers

如果你需要给某个请求添加HTTP头,可以使用headers参数,传递一个dict对象即可。 比如,如果你想给之前的例子指定 content-type可以这样:

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)

自定义Cookies

发送你自己的cookies给服务器,你可以为ClientSession对象指定cookies参数:

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"}}

注意:

访问httpbin.org/cookies 会看到以JSON形式返回的cookies。查阅会话中的cookies请看ClientSession.cookie_jar。

发起更复杂的POST请求

一般来说,如果你想以表单形式发送一些数据 - 就像HTML表单。那么只需要简单的将一个dict通过data参数传递就可以。传递的dict数据会自动编码:

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"
},
...
}

如果你想发送非表单形式的数据你可用str(字符串)代替dict(字典)。这些数据会直接发送出去。 例如,GitHub API v3 接受JSON编码POST/PATCH数据:

import json
url = 'https://api.github.com/some/endpoint'
payload = {'some': 'data'} async with session.post(url, data=json.dumps(payload)) as resp:
...

发送多部分编码文件(Multipart-Encoded)

上传多部分编码文件:

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

你也可以显式地设置文件名,文件类型:

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会自动将其以流的形式上传。查看StreamReader以获取支持的格式信息。

流式上传

aiohttp 支持多种形式的流式上传,允许你直接发送大文件而不必读到内存。

下面是个简单的例子,提供类文件对象即可:

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

或者你也可以使用aiohttp.streamer对象:

@aiohttp.streamer
def file_sender(writer, file_name=None):
with open(file_name, 'rb') as f:
chunk = f.read(2**16)
while chunk:
yield from writer.write(chunk)
chunk = f.read(2**16) # 之后你可以使用’file_sender‘传递给data: async with session.post('http://httpbin.org/post',
data=file_sender(file_name='huge_file')) as resp:
print(await resp.text())

同样可以使用StreamReader对象.

我们来看下如何把来自于另一个请求的内容作为文件上传并计算其SHA1值:

async def feed_stream(resp, stream):
h = hashlib.sha256() while True:
chunk = await resp.content.readany()
if not chunk:
break
h.update(chunk)
stream.feed_data(chunk) return h.hexdigest() resp = session.get('http://httpbin.org/post')
stream = StreamReader()
loop.create_task(session.post('http://httpbin.org/post', data=stream)) file_hash = await feed_stream(resp, stream)

因为响应对象的content属性是一个StreamReader实例,所以你可以将get和post请求连在一起用:

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

aiohttp基本及进阶使用的更多相关文章

  1. 小白学 Python 爬虫(32):异步请求库 AIOHTTP 基础入门

    人生苦短,我用 Python 前文传送门: 小白学 Python 爬虫(1):开篇 小白学 Python 爬虫(2):前置准备(一)基本类库的安装 小白学 Python 爬虫(3):前置准备(二)Li ...

  2. 学习python须知,Python基础进阶需掌握哪些知识点?

    Python基础进阶需要掌握哪些知识点?Python将是每个程序员的标配,有编程基础再掌握Python语言对于日后的升职加薪更有利.Python语言简洁利于理解,语法上相对容易能够让开发者更专注于业务 ...

  3. nodejs进阶(6)—连接MySQL数据库

    1. 建库连库 连接MySQL数据库需要安装支持 npm install mysql 我们需要提前安装按mysql sever端 建一个数据库mydb1 mysql> CREATE DATABA ...

  4. nodejs进阶(4)—读取图片到页面

    我们先实现从指定路径读取图片然后输出到页面的功能. 先准备一张图片imgs/dog.jpg. file.js里面继续添加readImg方法,在这里注意读写的时候都需要声明'binary'.(file. ...

  5. JavaScript进阶之路(一)初学者的开始

    一:写在前面的问题和话 一个javascript初学者的进阶之路! 背景:3年后端(ASP.NET)工作经验,javascript水平一般般,前端水平一般般.学习资料:犀牛书. 如有误导,或者错误的地 ...

  6. nodejs进阶(3)—路由处理

    1. url.parse(url)解析 该方法将一个URL字符串转换成对象并返回. url.parse(urlStr, [parseQueryString], [slashesDenoteHost]) ...

  7. nodejs进阶(5)—接收请求参数

    1. get请求参数接收 我们简单举一个需要接收参数的例子 如果有个查找功能,查找关键词需要从url里接收,http://localhost:8000/search?keyword=地球.通过前面的进 ...

  8. nodejs进阶(1)—输出hello world

    下面将带领大家一步步学习nodejs,知道怎么使用nodejs搭建服务器,响应get/post请求,连接数据库等. 搭建服务器页面输出hello world var  http  =  require ...

  9. [C#] 进阶 - LINQ 标准查询操作概述

    LINQ 标准查询操作概述 序 “标准查询运算符”是组成语言集成查询 (LINQ) 模式的方法.大多数这些方法都在序列上运行,其中的序列是一个对象,其类型实现了IEnumerable<T> ...

随机推荐

  1. Java-控制台传递参数

    今天组长叫我把所有的参数(写死的),用控制器输入,使其变成可变的. ------我的程序是需要读取文件的,控制台输入即,是文件放在哪我都可以读取. 比如我需要读取的demo.txt文件在D盘根目录下, ...

  2. Python初学者第三天 运算符、while循环

    3day Python基础语法 1.运算符:算数运算符.比较运算符.赋值运算符.逻辑运算符 A.算数运算符:a=10,b=3 + 加   a+b - 减  a-b * 乘  a*b / 除  a/b ...

  3. 乘风破浪:LeetCode真题_027_Remove Element

    乘风破浪:LeetCode真题_027_Remove Element 一.前言 这次是从数组中找到一个元素,然后移除该元素的所有结果,并且返回长度. 二.Remove Element 2.1 问题 2 ...

  4. Spring Boot 的 Security 安全控制

    Spring Security 是一个强大且高度可定制的身份验证和访问控制框架,完全基于 Spring 的应用程序的标准,Spring Security 为基于 Java EE 的企业应用程序提供了一 ...

  5. SQL SERVER 2005镜像配置(有无见证服务器都行)

    我用的是没有见证的,但找的文章里有镜像,所以都做一下补充,两个网址做的参考, 之所以在从他们那再补充一次是为了怕有一天他们的文章被删了我这还有个备用的,这两篇写的不错 其他的都不行 特别乱,这是找的最 ...

  6. python spawnv用法

    test.py import os import string def run(program, *args): file = program result = os.spawnv(os.P_WAIT ...

  7. QT5 视图坐标

    又出错了. . main.obj:-1: error: LNK2001: 无法解析的外部符号 "public: virtual struct QMetaObject const * __th ...

  8. BZOJ3998:[TJOI2015]弦论(SAM)

    Description 对于一个给定长度为N的字符串,求它的第K小子串是什么. Input 第一行是一个仅由小写英文字母构成的字符串S 第二行为两个整数T和K,T为0则表示不同位置的相同子串算作一个. ...

  9. 谈谈HTTP

    HTTP又称超文本传输协议,在互联网上广为流传和应用. 今天主要讲这么几个? a.针对HTTP下细分为: HTTP概念.Request和Response详解.Request中GET和POST的区别.说 ...

  10. Java继承访问权限

    JAVA 子类重写继承的方法时,不可以降低方法的访问权限,子类继承父类的访问修饰符要比父类的更大,也就是更加开放,假如我父类是protected修饰的,其子类只能是protected或者public, ...