异步:asyncio和aiohttp的一些应用(2)

时间:2023-01-08 13:01:29

转自:原文链接:http://www.cnblogs.com/ssyfj/p/9222342.html

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

异步:asyncio和aiohttp的一些应用(2)
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()
异步:asyncio和aiohttp的一些应用(2)

2.发起一个session请求

异步:asyncio和aiohttp的一些应用(2)
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()
异步:asyncio和aiohttp的一些应用(2)

除了上面的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参数中即可

异步:asyncio和aiohttp的一些应用(2)
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()
异步:asyncio和aiohttp的一些应用(2)

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字节

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

异步:asyncio和aiohttp的一些应用(2)
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"),]
异步:asyncio和aiohttp的一些应用(2)

注意:

async with session.get(url,params=params) as r:  #异步上下文管理器
with open(filename,"wb") as fp:  #普通上下文管理器

两者的区别:

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

__aenter__和__aexit__方法

异步:asyncio和aiohttp的一些应用(2)

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

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

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

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

异步:asyncio和aiohttp的一些应用(2)
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)
异步:asyncio和aiohttp的一些应用(2)

8.自定义cookie

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

异步:asyncio和aiohttp的一些应用(2)
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):
异步:asyncio和aiohttp的一些应用(2)

使用:

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

9.获取当前访问网站的cookie

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

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,请求头等

异步:asyncio和aiohttp的一些应用(2)
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"))
异步:asyncio和aiohttp的一些应用(2)
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。

异步:asyncio和aiohttp的一些应用(2)


异步:asyncio和aiohttp的一些应用(2)
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
异步:asyncio和aiohttp的一些应用(2)

异步:asyncio和aiohttp的一些应用(2)

总结:

当我们使用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维持链接池,限制并行连接的总量,当池满了,有请求退出再加入新请求

异步:asyncio和aiohttp的一些应用(2)
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)
异步:asyncio和aiohttp的一些应用(2)

限制同时打开限制同时打开连接到同一端点的数量((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)
异步:asyncio和aiohttp的一些应用(2)
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)
异步:asyncio和aiohttp的一些应用(2)

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

(4)post 大文件

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

异步:asyncio和aiohttp的一些应用(2)
@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())
异步:asyncio和aiohttp的一些应用(2)

(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的值:

异步:asyncio和aiohttp的一些应用(2)
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
异步:asyncio和aiohttp的一些应用(2)
 
 
 
 

异步:asyncio和aiohttp的一些应用(2)的更多相关文章

  1. Python学习---IO的异步[asyncio +aiohttp模块]

    aiohttp aiohttp是在asyncio模块基础上封装的一个支持HTTP请求的模块,内容比8.4.2[基于asyncio实现利用TCP模拟HTTP请求]更全面 安装aiohttp: pip3 ...

  2. 异步:asyncio和aiohttp的一些应用(1)

    1. asyncio 1.1asyncio/await 用法 async/await 是 python3.5中新加入的特性, 将异步从原来的yield 写法中解放出来,变得更加直观. 在3.5之前,如 ...

  3. 异步网络模块之aiohttp的使用(一)

    异步网络模块之aiohttp的使用(一) 平时我们也许用的更多的是requests模块,或者是requests_hml模块,但是他们都属于阻塞类型的不支持异步,速度很难提高,于是后来出现了异步的gre ...

  4. Python有了asyncio和aiohttp在爬虫这类型IO任务中多线程/多进程还有存在的必要吗?

    最近正在学习Python中的异步编程,看了一些博客后做了一些小测验:对比asyncio+aiohttp的爬虫和asyncio+aiohttp+concurrent.futures(线程池/进程池)在效 ...

  5. 异步网络编程aiohttp的使用

    aiohttp的使用 aiohttp Asynchronous HTTP Client/Server for asyncio and Python. Supports both Client and ...

  6. 爬虫----异步---高性能爬虫----aiohttp 和asycio 的使用

    前情提要: 首先膜拜loco大佬 肯定有人像我一样.不会异步,发一下. 一:性能比对 多进程,多线程,(这里不建议使用,太消耗性能) 进程池和线程池 (可以适当的使用) 单线程+异步协程   (推荐使 ...

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

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

  8. Python学习---IO的异步[asyncio模块(no-http)]

    Asyncio进行异步IO请求操作: 1. @asyncio.coroutine  装饰任务函数 2. 函数内配合yield from 和装饰器@asyncio.coroutine 配合使用[固定格式 ...

  9. asyncio 实现 aiohttp

    #asyncio 没有提供http协议的接口 aiohttp import asyncio import socket from urllib.parse import urlparse async ...

随机推荐

  1. 【UE4游戏开发】安装UE4时报SU-PQR1603错误的解决方法

    马三在开发过程中一直用的都是UE4.9版本(很久没有更新了.),因为功能都够用,所以也懒得去更新.这不最近UE4 发布了最新的4.14版本,本来想尝个鲜,试试新版的UE引擎怎么样,结果这一安装上就一直 ...

  2. infobright 导入 导出

    SET SQL_LOG_BIN = 0;select * into outfile 'mydata.cvs' fields terminated by ',' from table1;load dat ...

  3. iOS优化内存方法推荐

    1. 用ARC管理内存 ARC(Automatic ReferenceCounting, 自动引用计数)和iOS5一起发布,它避免了最常见的也就是经常是由于我们忘记释放内存所造成的内存泄露.它自动为你 ...

  4. 在线App开发平台——应用之星傻瓜式开发平台

    随着智能手机及APP应用程序的普及,越来越多的企业和个人意识到APP的营销价值,出于对技术的敬畏,很多企业下意识认为开发APP是一个有难度的技术活,所以很多时候有心无力,也担心APP的后续的技术支持. ...

  5. resumable.js —— 基于 HTML 5 File API 的文件上传组件 支持续传后台c#实现

    在git上提供了java.nodejs.c#后台服务方式:在这里我要用c#作为后台服务:地址请见:https://github.com/23/resumable.js 我现在visual studio ...

  6. 中颖电子AD操作

    #define ADC_DIS 0 #define ADC_ENB 1 //ADC通道号定义 #define ADC_Chanel0 (unsigned char)(0x00<<1) #d ...

  7. SDN学习之Mininet验证OpenFlow协议版本

    最近学习如何使用mininet,但是,刚刚开始时一直无法知道如何查看OpenFlow协议的版本,通过查阅网上的资料,从SDNLAB中,学习到了如何验证,mininet自身基于OpenFlow13版本的 ...

  8. 4&period;jsp的内置对象

    1.jsp有九大内置对象 out request response session application page pagecontext exception config 2.用户发请求 requ ...

  9. 中文代码示例之Electron桌面应用开发初体验

    参考: 打造你的第一个 Electron 应用 首先运行下面在目录下创建package.json: $ npm init 去掉了一些无关项后内容如下: { "name": &quo ...

  10. vue中&dollar;router&period;push打开新窗口

    在vue中使用 this.$router.push({ path:  '/home' }) 默认是替代本窗口 如果想新开一个窗口,可以使用下面的方式: let routeData = this.$ro ...