本文最后更新于:2020年12月24日 上午
简介 requests
是一个阻塞式HTTP请求库,发出一个请求后,程序会一直等待服务器响应,得到响应后,程序才会进行下一步处理。这种等待会大大降低爬取效率aiohttp
是一个提供异步web服务的库,能让你的程序可以在等待的过程中做一切其他的事情,提高效率
文档信息 官方文档:https://docs.aiohttp.org/en/stable/ github:https://github.com/aio-libs/aiohttp
安装
另外,官方推荐安装 字符编码检测库 cchardet,加速DNS解析库aiodns
pip install cchardet aiodns
入门 基础 import aiohttpprint ('Hello Aiohttp' )async with aiohttp.ClientSession() as session: async with session.get('http://httpbin.org/get' ) as resp: print (resp.status) print (await resp.text())
这段代码创建了一个session
以用作访问,但最好不要每一次访问都创建session
,如果可以的话同一个网站用同一个session来进行访问
实际上除了get()
还有一些其它的方法
session.post('http://httpbin.org/post' , data =b'data' ) session.put('http://httpbin.org/put' , data =b'data' ) session.delete('http://httpbin.org/delete' )... ...
带参数的get请求 传入params
参数即可
params = {'key1' : 'value1' , 'key2' : 'value2' }async with session.get ('http://httpbin.org/get' , params =params ) as resp: print(resp.url)
关于url转换 aiohttp
默认会在发送请求之前会在内部执行URL规范化 比如将url中的中文转为其它编码 如果不希望进行这个过程,可以传入encoded=True
禁用
await session.get ( URL('http://example.com/%30' , encoded =True ))
需要注意的是,如果你get方法
中传入了params
参数,那么这个禁用会无效
二进制响应 如果响应是二进制文件,那么需要用read()
来获取
Json请求 session
的任何方法都可以传入json
参数
async with aiohttp.ClientSession() as session : async with session.post(url , json={'test' : 'object' })
session
会使用python
自带的json
模块来进行序列化 你也可以使用比它更快的ujson
模块来进行这个过程
import ujsonasync with aiohttp.ClientSession( json_serialize=ujson.dumps) as session : await session.post(url , json={'test' : 'object' })
Json响应 resp.json()
可以直接解析json
async with session.get ('https://api.github.com/events' ) as resp: print (await resp.json())
响应内容流 read()
,json()
、text()
方法非常方便,但应该要谨慎使用。这些方法会将整个响应加载到内存中。要是响应很大,就会造成问题
with open (filename, 'wb' ) as fd: while True : chunk = await resp.content.read(chunk_size) if not chunk : break fd.write(chunk )
你可以一些一些的去处理响应
post请求 传入表单参数即可,编码会自动完成
payload = {'key1' : 'value1' , 'key2' : 'value2' }async with session.post('http://httpbin.org/post' , data=payload) as resp: print (await resp.text())
如果只希望传递字符,可以用data
参数
async with session.post(url , data='Тест' ) as resp : ...
上传文件 一点点载入,一点点上传
async def file_sender (file_name=None ): async with aiofiles.open (file_name, 'rb' ) as f: chunk = await f.read(64 *1024 ) while chunk: yield chunk chunk = await f.read(64 *1024 )async with session.post('http://httpbin.org/post' , data=file_sender(file_name='huge_file' )) as resp: print(await resp.text())
WebSockets async with session.ws_connect('http://example.org/ws' ) as ws: async for msg in ws: if msg.type == aiohttp.WSMsgType.TEXT: if msg.data == 'close cmd' : await ws.close() break else : await ws.send_str(msg.data + '/answer' ) elif msg.type == aiohttp.WSMsgType.ERROR: break
You must use the only websocket task for both reading (e.g. await ws.receive() or async for msg in ws:) and writing but may have multiple writer tasks which can only send data asynchronously (by await ws.send_str(‘data’) for example).
超时 超时设置存储在ClientTimeout
对象中 默认情况下,这个超时的时间是5分钟 给seesion设置超时
timeout = aiohttp.ClientTimeout(total =60) async with aiohttp.ClientSession(timeout =timeout ) as session: ...
给这次get请求设置超时
async with session.get (url, timeout =timeout ) as resp: ...
ClientTimeout
接收多个参数作为超时标准
aiohttp.ClientTimeout(total =5*60, connect =None, sock_connect =None, sock_read =None)
total 总时长
connect 建立新连接时间 或 在连接池中等待的时间
sock_connect A timeout for connecting to a peer for a new connection, not given from a pool
sock_read 从对等方读取新数据部分之间的最大允许超时时间
代理 你可以在session.get()
中设置你的proxy:
async with session.get(url, proxy=your_proxy_url) as response: return BeautifulSoup(await response.content, 'html.parser' )
如果你的IP需要认证,可以这样设置:
proxy = 'http://your_user:your_password@your_proxy_url:your_proxy_port' async with session.get(url, proxy=proxy) as response: return BeautifulSoup(await response.content, 'html.parser' )
或者是这样设置:
proxy = 'http://your_proxy_url:your_proxy_port' proxy_auth = aiohttp.BasicAuth('your_user' , 'your_password' )async with session.get(url, proxy=proxy, proxy_auth=proxy_auth) as response: return BeautifulSoup(await response.content, 'html.parser' )