python协程爬虫-aiohttp+aiomultiprocess使用
aiohttp
aiohttp是基于asyncio的一个异步http客户端和服务器
官方文档:https://aiohttp.readthedocs.io/en/stable/client_quickstart.html
这里我主要记录客户端的操作
简单实用例子
async def funct(index): print("start ", index) async with aiohttp.ClientSession() as session: async with session.get("https://movie.douban.com/top250?start=0", timeout=5) as resp: print(resp.status) print(await resp.text()) print("end ", index)
是要先创建一个会话,然后使用这个会话进行请求
aiohttp.ClientSession()
创建会话,session提供了各种请求方法,如get、post、delete、put等
这里认识了新的关键字async with,因为是协程的上下文管理,所以多了async关键字
这个不是强制使用的,你也可以自己手动关闭会话,但是一定要记得关闭
注意:
1、不要为每个请求创建会话。每个应用程序很可能需要一个会话来执行所有请求。
2、aiohttp在发送请求之前在内部执行URL 规范化。要禁用规范化,请使用encoded=True
参数进行URL构建
获取响应信息
resp.status # 状态码 await resp.text() # 获取响应正文,可以指定编码 await resp.read() # 读取二进制响应内容 await resp.json() # 获取json响应内容 await resp.content.read(size) # 读取流
注意事项:aiohttp是在await resp.text()之后才发起请求的,所以必须调用之后才能获取响应的内容,不然会出现异常aiohttp.client_exceptions.ClientConnectionError: Connection closed
aiomultiprocess
asyncio和多处理本身是有用的,但有局限性:asyncio仍然不能超过GIL的速度,并且多处理一次只能处理一个任务。但是,他们在一起可以充分实现自己的真正潜力。
aiomultiprocess提供了一个简单的界面,同时在每个子进程上运行完整的asyncio事件循环,从而实现了Python应用程序从未有过的并发级别。每个子进程可以一次执行多个协程,仅受工作量和可用内核数限制。
注:aiomultiprocess需要Python 3.6或更高版本
用法
在子进程中执行协程
import asyncio from aiohttp import request from aiomultiprocess import Process async def put(url, params): async with request("PUT", url, params=params) as response: pass async def main(): p = Process(target=put, args=("https://jreese.sh", {})) await p if __name__ == "__main__": asyncio.run(main())
如果您想从协程中获取结果Worker
,请使用以下方法:
import asyncio from aiohttp import request from aiomultiprocess import Worker async def get(url): async with request("GET", url) as response: return await response.text("utf-8") async def main(): p = Worker(target=get, args=("https://jreese.sh", )) response = await p if __name__ == "__main__": asyncio.run(main())
如果您需要一个托管的工作进程池,请使用Pool
:
import asyncio
from aiohttp import request
from aiomultiprocess import Pool
async def get(url):
async with request("GET", url) as response:
return await response.text("utf-8")
async def main():
urls = ["https://jreese.sh", ...]
async with Pool() as pool:
result = await pool.map(get, urls)
if __name__ == "__main__":
asyncio.run(main())