python aiohttp的使用详解


Posted in Python onJune 20, 2019

1.aiohttp的简单使用(配合asyncio模块)

import asyncio,aiohttp

async def fetch_async(url):
 print(url)
 async with aiohttp.request("GET",url) as r:
  reponse = await r.text(encoding="utf-8")#或者直接await r.read()不编码,直接读取,适合于图像等无法编码文件
  print(reponse)

tasks = [fetch_async('http://www.baidu.com/'), fetch_async('http://www.chouti.com/')]

event_loop = asyncio.get_event_loop()
results = event_loop.run_until_complete(asyncio.gather(*tasks))
event_loop.close()

2.发起一个session请求

import asyncio,aiohttp

async def fetch_async(url):
 print(url)
 async with aiohttp.ClientSession() as session:#协程嵌套,只需要处理最外层协程即可fetch_async
  async with session.get(url) as resp:
   print(resp.status)
   print(await resp.text())
#因为这里使用到了await关键字,实现异步,所有他上面的函数体需要声明为异步async

tasks = [fetch_async('http://www.baidu.com/'), fetch_async('http://www.cnblogs.com/ssyfj/')]

event_loop = asyncio.get_event_loop()
results = event_loop.run_until_complete(asyncio.gather(*tasks))
event_loop.close()

除了上面的get方法外,会话还支持post,put,delete....等

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对象,内部包含了一个连接池,并且将会保持连接和连接复用(默认开启)可以加快整体的性能。

3.在url中传递参数(其实与requests模块使用大致相同)

只需要将参数字典,传入params参数中即可[code]import asyncio,aiohttp

import asyncio,aiohttp

async def func1(url,params):
 async with aiohttp.ClientSession() as session:
  async with session.get(url,params=params) as r:
   print(r.url)
   print(await r.read())

tasks = [func1('https://www.ckook.com/forum.php',{"gid":6}),]

event_loop = asyncio.get_event_loop()
results = event_loop.run_until_complete(asyncio.gather(*tasks))
event_loop.close()

4.获取响应内容(由于获取响应内容是一个阻塞耗时过程,所以我们使用await实现协程切换)

(1)使用text()方法

async def func1(url,params):
 async with aiohttp.ClientSession() as session:
  async with session.get(url,params=params) as r:
   print(r.url)
   print(r.charset)#查看默认编码为utf-8
   print(await r.text())
#不编码,则是使用默认编码
使用encoding指定编码

(2)使用read()方法,不进行编码,为字节形式

async def func1(url,params):
 async with aiohttp.ClientSession() as session:
  async with session.get(url,params=params) as r:
   print(r.url)
   print(await r.read())

(3)注意:text(),read()方法是把整个响应体读入内存,如果你是获取大量的数据,请考虑使用”字节流“(StreamResponse)

5.特殊响应内容json(和上面一样)

async def func1(url,params):
 async with aiohttp.ClientSession() as session:
  async with session.get(url,params=params) as r:
   print(r.url)
   print(r.charset)
   print(await r.json())#可以设置编码,设置处理函数

6.字节流形式获取数据(不像text,read一次获取所有数据)注意:我们获取的session.get()是Response对象,他继承于StreamResponse

async def func1(url,params):
 async with aiohttp.ClientSession() as session:
  async with session.get(url,params=params) as r:
   print(await r.content.read(10)) #读取前10字节

下面字节流形式读取数据,保存文件

async def func1(url,params,filename):
 async with aiohttp.ClientSession() as session:
  async with session.get(url,params=params) as r:
   with open(filename,"wb") as fp:
    while True:
     chunk = await r.content.read(10)
     if not chunk:
      break
     fp.write(chunk)

tasks = [func1('https://www.ckook.com/forum.php',{"gid":6},"1.html"),]

注意:

async with session.get(url,params=params) as r:#异步上下文管理器

with open(filename,"wb") as fp:
#普通上下文管理器

两者的区别:

在于异步上下文管理器中定义了

__aenter__和__aexit__方法

python aiohttp的使用详解

异步上下文管理器指的是在enterexit方法处能够暂停执行的上下文管理器

为了实现这样的功能,需要加入两个新的方法:__aenter____aexit__。这两个方法都要返回一个 awaitable类型的值。

推文:异步上下文管理器async with和异步迭代器async for

7.自定义请求头(和requests一样)

async def func1(url,params,filename):
 async with aiohttp.ClientSession() as session:
  headers = {'Content-Type':'text/html; charset=utf-8'}
  async with session.get(url,params=params,headers=headers) as r:
   with open(filename,"wb") as fp:
    while True:
     chunk = await r.content.read(10)
     if not chunk:
      break
     fp.write(chunk)

8.自定义cookie

注意:对于自定义cookie,我们需要设置在ClientSession(cookies=自定义cookie字典),而不是session.get()中

class ClientSession:

 def __init__(self, *, connector=None, loop=None, cookies=None,
     headers=None, skip_auto_headers=None,
     auth=None, json_serialize=json.dumps,
     request_class=ClientRequest, response_class=ClientResponse,
     ws_response_class=ClientWebSocketResponse,
     version=http.HttpVersion11,
     cookie_jar=None, connector_owner=True, raise_for_status=False,
     read_timeout=sentinel, conn_timeout=None,
     timeout=sentinel,
     auto_decompress=True, trust_env=False,
     trace_configs=None):

使用:

cookies = {'cookies_are': 'working'}
async with ClientSession(cookies=cookies) as session:

10.获取网站的响应状态码

async with session.get(url) as resp:
 print(resp.status)

11.查看响应头

resp.headers 来查看响应头,得到的值类型是一个dict:

resp.raw_headers

查看原生的响应头,字节类型

12.查看重定向的响应头(我们此时已经到了新的网址,向之前的网址查看)

resp.history#查看被重定向之前的响应头

13.超时处理

默认的IO操作都有5分钟的响应时间 我们可以通过 timeout 进行重写:

async with session.get('https://github.com', timeout=60) as r:
 ...

如果 timeout=None 或者 timeout=0 将不进行超时检查,也就是不限时长。

14.ClientSession 用于在多个连接之间(同一网站)共享cookie,请求头等

async def func1():
 cookies = {'my_cookie': "my_value"}
 async with aiohttp.ClientSession(cookies=cookies) as session:
  async with session.get("https://segmentfault.com/q/1010000007987098") as r:
   print(session.cookie_jar.filter_cookies("https://segmentfault.com"))
  async with session.get("https://segmentfault.com/hottest") as rp:
   print(session.cookie_jar.filter_cookies(https://segmentfault.com))
Set-Cookie: PHPSESSID=web2~d8grl63pegika2202s8184ct2q
Set-Cookie: my_cookie=my_value
Set-Cookie: PHPSESSID=web2~d8grl63pegika2202s8184ct2q
Set-Cookie: my_cookie=my_value

我们最好使用session.cookie_jar.filter_cookies()获取网站cookie,不同于requests模块,虽然我们可以使用rp.cookies有可能获取到cookie,但似乎并未获取到所有的cookies。

python aiohttp的使用详解

async def func1():
 cookies = {'my_cookie': "my_value"}
 async with aiohttp.ClientSession(cookies=cookies) as session:
  async with session.get("https://segmentfault.com/q/1010000007987098") as rp:
   print(session.cookie_jar.filter_cookies("https://segmentfault.com"))
   print(rp.cookies)#Set-Cookie: PHPSESSID=web2~jh3ouqoabvr4e72f87vtherkp6; Domain=segmentfault.com; Path=/
#首次访问会获取网站设置的cookie
  async with session.get("https://segmentfault.com/hottest") as rp:
   print(session.cookie_jar.filter_cookies("https://segmentfault.com"))
   print(rp.cookies)
#为空,服务端未设置cookie
  async with session.get("https://segmentfault.com/newest") as rp:
   print(session.cookie_jar.filter_cookies("https://segmentfault.com"))
   print(rp.cookies)
#为空,服务端未设置cookie

python aiohttp的使用详解

总结:

当我们使用rp.cookie时,只会获取到当前url下设置的cookie,不会维护整站的cookie

而session.cookie_jar.filter_cookies("https://segmentfault.com")会一直保留这个网站的所有设置cookies,含有我们在会话时设置的cookie,并且会根据响应修改更新cookie。这个才是我们需要的

而我们设置cookie,也是需要在aiohttp.ClientSession(cookies=cookies)中设置

ClientSession 还支持 请求头,keep-alive连接和连接池(connection pooling)

15.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)

16.控制同时连接的数量(连接池)

TCPConnector维持链接池,限制并行连接的总量,当池满了,有请求退出再加入新请求

async def func1():
 cookies = {'my_cookie': "my_value"}
 conn = aiohttp.TCPConnector(limit=2)#默认100,0表示无限
 async with aiohttp.ClientSession(cookies=cookies,connector=conn) as session:
  for i in range(7,35):
   url = "https://www.ckook.com/list-%s-1.html"%i
   async with session.get(url) as rp:
    print('---------------------------------')
    print(rp.status)

限制同时打开限制同时打开连接到同一端点的数量((host, port, is_ssl) 三的倍数),可以通过设置 limit_per_host 参数:

limit_per_host: 同一端点的最大连接数量。同一端点即(host, port, is_ssl)完全相同

conn = aiohttp.TCPConnector(limit_per_host=30)#默认是0

在协程下测试效果不明显

17.自定义域名解析地址

我们可以指定域名服务器的 IP 对我们提供的get或post的url进行解析:

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

18.设置代理

aiohttp支持使用代理来访问网页:

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)

19.post传递数据的方法

(1)模拟表单

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

注意:data=dict的方式post的数据将被转码,和form提交数据是一样的作用,如果你不想被转码,可以直接以字符串的形式 data=str 提交,这样就不会被转码。

(2)post json

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

其实json.dumps(payload)返回的也是一个字符串,只不过这个字符串可以被识别为json格式

(3)post 小文件

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)

如果将文件对象设置为数据参数,aiohttp将自动以字节流的形式发送给服务器。

(4)post 大文件

aiohttp支持多种类型的文件以流媒体的形式上传,所以我们可以在文件未读入内存的情况下发送大文件。

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

(5)从一个url获取文件后,直接post给另一个url

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

(6)post预压缩数据

在通过aiohttp发送前就已经压缩的数据, 调用压缩函数的函数名(通常是deflate 或 zlib)作为content-encoding的值:

async def my_coroutine(session, headers, my_data):
 data = zlib.compress(my_data)
 headers = {'Content-Encoding': 'deflate'}
 async with session.post('http://httpbin.org/post',
       data=data,
       headers=headers)
  pass

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
Python实现简单状态框架的方法
Mar 19 Python
Python实现PS图像明亮度调整效果示例
Jan 23 Python
Python2和Python3中urllib库中urlencode的使用注意事项
Nov 26 Python
Django实现学员管理系统
Feb 26 Python
python中删除某个元素的方法解析
Nov 05 Python
详解pycharm2020.1.1专业版安装指南(推荐)
Aug 07 Python
Python三维绘图之Matplotlib库的使用方法
Sep 20 Python
浅析python 通⽤爬⾍和聚焦爬⾍
Sep 28 Python
用python实现一个简单计算器(完整DEMO)
Oct 14 Python
python uuid生成唯一id或str的最简单案例
Jan 13 Python
python基础之匿名函数详解
Apr 21 Python
如何使用Python对NetCDF数据做空间相关分析
Apr 21 Python
Python 中Django验证码功能的实现代码
Jun 20 #Python
Puppeteer使用示例详解
Jun 20 #Python
获取django框架orm query执行的sql语句实现方法分析
Jun 20 #Python
Python使用LDAP做用户认证的方法
Jun 20 #Python
Python OpenCV中的resize()函数的使用
Jun 20 #Python
python中的句柄操作的方法示例
Jun 20 #Python
使用python获取(宜宾市地震信息)地震信息
Jun 20 #Python
You might like
自制短波长线天线频率预选器 - 成功消除B2K之流的镜像
2021/03/02 无线电
关于PHPDocument 代码注释规范的总结
2013/06/25 PHP
php将HTML表格每行每列转为数组实现采集表格数据的方法
2015/04/03 PHP
js自定义事件及事件交互原理概述(二)
2013/02/01 Javascript
jquery动态添加删除div 具体实现
2013/07/20 Javascript
获取3个数组不重复的值的具体实现
2013/12/30 Javascript
轻松创建nodejs服务器(1):一个简单nodejs服务器例子
2014/12/18 NodeJs
使用jQuery简单实现模拟浏览器搜索功能
2014/12/21 Javascript
Javascript实现的简单右键菜单类
2015/09/23 Javascript
JavaScript类型检测之typeof 和 instanceof 的缺陷与优化
2016/01/13 Javascript
在其他地方你学不到的jQuery小贴士和技巧(欢迎收藏)
2016/01/20 Javascript
AngularJS模块详解及示例代码
2016/08/17 Javascript
AngularJS入门教程之REST和定制服务详解
2016/08/19 Javascript
js实现微博发布小功能
2017/01/12 Javascript
vue axios请求拦截实例代码
2018/03/29 Javascript
vue-router beforeEach跳转路由验证用户登录状态
2018/12/26 Javascript
vue 中Virtual Dom被创建的方法
2019/04/15 Javascript
用jQuery实现抽奖程序
2020/04/12 jQuery
JQuery使用数组遍历跳出each循环
2020/09/01 jQuery
[01:01:51]EG vs VG Supermajor小组赛B组 BO3 第二场 6.2
2018/06/03 DOTA
浅谈python中的数字类型与处理工具
2017/08/02 Python
Python爬虫使用Selenium+PhantomJS抓取Ajax和动态HTML内容
2018/02/23 Python
Python实现的登录验证系统完整案例【基于搭建的MVC框架】
2019/04/12 Python
使用Python的turtle模块画国旗
2019/09/24 Python
django实现将后台model对象转换成json对象并传递给前端jquery
2020/03/16 Python
python获取百度热榜链接的实例方法
2020/08/25 Python
Python装饰器如何实现修复过程解析
2020/09/05 Python
购买澳大利亚最好的服装和内衣在线:BONDS
2016/10/14 全球购物
Maisons du Monde德国:法国家具和装饰的市场领导者
2019/07/26 全球购物
英国名牌男装店:Standout
2021/02/17 全球购物
授权委托书协议书
2014/10/16 职场文书
公司股份转让协议书范本
2015/01/28 职场文书
一百条裙子读书笔记
2015/07/01 职场文书
python保存大型 .mat 数据文件报错超出 IO 限制的操作
2021/05/10 Python
深入详解JS函数的柯里化
2021/06/09 Javascript
Windows环境下实现批量执行Sql文件
2021/10/05 SQL Server