python aiohttp的使用详解

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__方法

异步上下文管理器指的是在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。

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

总结:

当我们使用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

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

(0)

相关推荐

  • Python中利用aiohttp制作异步爬虫及简单应用

    摘要: 简介 asyncio可以实现单线程并发IO操作,是Python中常用的异步处理模块.关于asyncio模块的介绍,笔者会在后续的文章中加以介绍,本文将会讲述一个基于asyncio实现的HTTP框架--aiohttp,它可以帮助我们异步地实现HTTP请求,从而使得我们的程序效率大大提高. 简介 asyncio可以实现单线程并发IO操作,是Python中常用的异步处理模块.关于asyncio模块的介绍,笔者会在后续的文章中加以介绍,本文将会讲述一个基于asyncio实现的HTTP框架--ai

  • Python中asyncio与aiohttp入门教程

    很多朋友对异步编程都处于"听说很强大"的认知状态.鲜有在生产项目中使用它.而使用它的同学,则大多数都停留在知道如何使用 Tornado.Twisted.Gevent 这类异步框架上,出现各种古怪的问题难以解决.而且使用了异步框架的部分同学,由于用法不对,感觉它并没牛逼到哪里去,所以很多同学做 Web 后端服务时还是采用 Flask.Django等传统的非异步框架. 从上两届 PyCon 技术大会看来,异步编程已经成了 Python 生态下一阶段的主旋律.如新兴的 Go.Rust.Eli

  • python aiohttp的使用详解

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

  • MySQL数据库设计之利用Python操作Schema方法详解

    弓在箭要射出之前,低声对箭说道,"你的自由是我的".Schema如箭,弓似Python,选择Python,是Schema最大的自由.而自由应是一个能使自己变得更好的机会. Schema是什么? 不管我们做什么应用,只要和用户输入打交道,就有一个原则--永远不要相信用户的输入数据.意味着我们要对用户输入进行严格的验证,web开发时一般输入数据都以JSON形式发送到后端API,API要对输入数据做验证.一般我都是加很多判断,各种if,导致代码很丑陋,能不能有一种方式比较优雅的验证用户数据呢

  • Python之str操作方法(详解)

    1. str.format():使用"{}"占位符格式化字符串(占位符中的索引号形式和键值对形式可以混合使用). >>> string = 'python{}, django{}, tornado{}'.format(2.7, 'web', 'tornado') # 有多少个{}占位符就有多少个值与其对应,按照顺序"填"进字符串中 >>> string 'python2.7, djangoweb, tornadotornado'

  • 基于python时间处理方法(详解)

    在处理数据和进行机器学习的时候,遇到了大量需要处理的时间序列.比如说:数据库读取的str和time的转化,还有time的差值计算.总结一下python的时间处理方面的内容. 一.字符串和时间序列的转化 time.strptime():字符串=>时间序列 time.strftime():时间序列=>字符串 import time start = "2017-01-01" end = "2017-8-12" startTime = time.strptime

  • Python探索之SocketServer详解

    SocketServer,网络通信服务器,是Python标准库中的一个模块,其作用是创建网络服务器.SocketServer模块定义了一些类来处理诸如TCP.UDP.UNIX流和UNIX数据报之上的同步网络请求. SocketServer模块处理网络请求的功能,可以通过两个主要的类来实现:一个是服务器类,一个是请求处理类. 服务器类 处理通信问题,如监听一个套接字并接收连接等: 请求处理类 处理"协议"问题,如解释到来的数据.处理数据并把数据发回给客户端等. 这种实现将服务器的实现过程

  • python学习 流程控制语句详解

    ###################### 分支语句 python3.5 ################ #代码的缩进格式很重要 建议4个空格来控制 #根据逻辑值(True,Flase)判断程序的运行方向 # Ture:表示非空的量(String,tuple元组 .list.set.dictonary),所有非零的数字 # False:0,None .空的量 #逻辑表达式 可以包含 逻辑运算符 and or not if: ##################################

  • Python 调用Java实例详解

    Python 调用Java实例详解 前言: Python 对服务器端编程不如Java 所以这方面可能要调用Java代码 前提: Linux 环境  1 安装 jpype1 安装后测试代码: from jpype import * startJVM(getDefaultJVMPath(), "-ea") java.lang.System.out.println("Hello World") shutdownJVM() 2 调用非jdk的jar包, test.jar 包

  • python 编程之twisted详解及简单实例

    python 编程之twisted详解 前言: 我不擅长写socket代码.一是用c写起来比较麻烦,二是自己平时也没有这方面的需求.等到自己真正想了解的时候,才发现自己在这方面确实有需要改进的地方.最近由于项目的原因需要写一些Python代码,才发现在python下面开发socket是一件多么爽的事情. 对于大多数socket来说,用户其实只要关注三个事件就可以了.这分别是创建.删除.和收发数据.python中的twisted库正好可以帮助我们完成这么一个目标,实用起来也不麻烦.下面的代码来自t

  • Python 文件操作的详解及实例

    Python 文件操作的详解及实例 一.文件操作 1.对文件操作流程 打开文件,得到文件句柄并赋值给一个变量 通过句柄对文件进行操作 关闭文件 现有文件如下: 昨夜寒蛩不住鸣. 惊回千里梦,已三更. 起来独自绕阶行. 人悄悄,帘外月胧明. 白首为功名,旧山松竹老,阻归程. 欲将心事付瑶琴. 知音少,弦断有谁听. f = open('小重山') #打开文件 data=f.read()#获取文件内容 f.close() #关闭文件 注意:if in the win,hello文件是utf8保存的,打

  • Python的语言类型(详解)

    Python 是强类型的动态脚本语言 . 强类型:不允许不同类型相加 动态:不使用显示数据类型声明,且确定一个变量的类型是在第一次给它赋值的时候 脚本语言:一般也是解释型语言,运行代码只需要一个解释器,不需要编译 强类型语言和弱类型语言 1.强类型语言:使之强制数据类型定义的语言.没有强制类型转化前,不允许两种不同类型的变量相互操作.强类型定义语言是类型安全的语言,如Java.C# 和 python,比如Java中"int i = 0.0;"是无法通过编译的: 2.弱类型语言:数据类型

随机推荐