aiohttp基本及进阶使用
客户端使用
发起请求
让我们从导入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":{...
gzip和defalte传输编码会自动解码。 你也可以使其支持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类的实例。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(), text()了。
获取请求信息
ClientResponse(客户端响应)对象含有request_info(请求信息),主要是url和headers信息。 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基本及进阶使用的更多相关文章
- 小白学 Python 爬虫(32):异步请求库 AIOHTTP 基础入门
人生苦短,我用 Python 前文传送门: 小白学 Python 爬虫(1):开篇 小白学 Python 爬虫(2):前置准备(一)基本类库的安装 小白学 Python 爬虫(3):前置准备(二)Li ...
- 学习python须知,Python基础进阶需掌握哪些知识点?
Python基础进阶需要掌握哪些知识点?Python将是每个程序员的标配,有编程基础再掌握Python语言对于日后的升职加薪更有利.Python语言简洁利于理解,语法上相对容易能够让开发者更专注于业务 ...
- nodejs进阶(6)—连接MySQL数据库
1. 建库连库 连接MySQL数据库需要安装支持 npm install mysql 我们需要提前安装按mysql sever端 建一个数据库mydb1 mysql> CREATE DATABA ...
- nodejs进阶(4)—读取图片到页面
我们先实现从指定路径读取图片然后输出到页面的功能. 先准备一张图片imgs/dog.jpg. file.js里面继续添加readImg方法,在这里注意读写的时候都需要声明'binary'.(file. ...
- JavaScript进阶之路(一)初学者的开始
一:写在前面的问题和话 一个javascript初学者的进阶之路! 背景:3年后端(ASP.NET)工作经验,javascript水平一般般,前端水平一般般.学习资料:犀牛书. 如有误导,或者错误的地 ...
- nodejs进阶(3)—路由处理
1. url.parse(url)解析 该方法将一个URL字符串转换成对象并返回. url.parse(urlStr, [parseQueryString], [slashesDenoteHost]) ...
- nodejs进阶(5)—接收请求参数
1. get请求参数接收 我们简单举一个需要接收参数的例子 如果有个查找功能,查找关键词需要从url里接收,http://localhost:8000/search?keyword=地球.通过前面的进 ...
- nodejs进阶(1)—输出hello world
下面将带领大家一步步学习nodejs,知道怎么使用nodejs搭建服务器,响应get/post请求,连接数据库等. 搭建服务器页面输出hello world var http = require ...
- [C#] 进阶 - LINQ 标准查询操作概述
LINQ 标准查询操作概述 序 “标准查询运算符”是组成语言集成查询 (LINQ) 模式的方法.大多数这些方法都在序列上运行,其中的序列是一个对象,其类型实现了IEnumerable<T> ...
随机推荐
- 插入图片新方式:data:image
我们在使用<img>标签和给元素添加背景图片时,不一定要使用外部的图片地址,也可以直接把图片数据定义在页面上.对于一些“小”的数据,可以在网页中直接嵌入,而不是从外部文件载入. 如何使用 ...
- Beyond Compare 4 使用方法
一 : 二 : 三 :
- 数据仓库四个特点(面向主题的(Subject Oriented)、集成的(Integrate)、相对稳定的(Non-Volatile)、反映历史变化(Time Variant))
1.面向主题. 数据仓库中的数据是按照一定的主题域进行组织. 主题是一个抽象的概念,是指用户使用数据仓库进行决策时所关心的重点方面,一个主题通常与多个操作型信息系统相关.而操作型数据库的数据组织面向事 ...
- 嵌入式开发板LInux更新系统、安装软件、下载资源碰到的问题
CAfile: /etc/ssl/certs/ca-certificates.crt CRLfile: none 先同步系统时间 shell 输入命令 date 如果显示的时间跟你本地时间不一样,先设 ...
- mysql5.7 误删管理员root账户
1.停止数据库,并在mysql配置文件my.cnf中添加skip-grant-tables参数到[mysqld]配置块中 2. 执行 systemctl start mysqld 3. 执行 mysq ...
- 读高性能JavaScript编程 第一章
草草的看完第一章,虽然看的是译文也是感觉涨姿势了, 我来总结一下: 由于 大多数浏览器都是 single process 处理 ui updatas and js execute 于是产生问题: js ...
- SDN 第五次上机作业
1.搭建如下拓扑并连接控制器 2.下发相关流表和组表实现负载均衡 s1: s2: s3: s4: 3.抓包分析验证负载均衡 s4-eth1: s4-eth2: s4-eth3
- Django商城项目笔记No.11用户部分-QQ登录1获取QQ登录网址
Django商城项目笔记No.11用户部分-QQ登录 QQ登录,亦即我们所说的第三方登录,是指用户可以不在本项目中输入密码,而直接通过第三方的验证,成功登录本项目. 若想实现QQ登录,需要成为QQ互联 ...
- 极限编程核心价值:反馈(Feedback)
原文:https://deviq.com/feedback 极限编程核心价值:简单(Simplicity) 极限编程核心价值:沟通(Communication) 极限编程核心价值:反馈(Feedbac ...
- Spark项目之电商用户行为分析大数据平台之(十)IDEA项目搭建及工具类介绍
一.创建Maven项目 创建项目,名称为LogAnalysis 二.常用工具类 2.1 配置管理组建 ConfigurationManager.java import java.io.InputStr ...