- 单线程+多任务异步协程:pip install asyncio
- 特殊的函数
- 如果一个函数的定义被async修饰后,则该函数就变成了一个特殊的函数
- 特殊之处:
- 该特殊的函数调用后,函数内部的实现语句不会被立即执行
- 该特殊函数被调用后会返回一个协程对象
- 协程对象
- 对象。通过特殊函数的调用返回一个协程对象。
- 协程 == 特殊函数 == 一组指定的 *** 作
- 协程 == 一组指定的 *** 作
- 任务对象
- 任务对象就是一个高级的协程对象。(任务对象就是对协程对象的进一步封装)
- 任务 == 协程 == 特殊函数 == 一组指定 *** 作
- 任务 == 一组指定的 *** 作
- 如何创建一个任务对象:
- asyncio.ensure_future(协程对象)
- 任务对象的高级之处:
- 可以给任务对象绑定回调:
- task.add_done_callback(task_callback)
- 回调函数的调用时机:
- 任务被执行结束后,才可以调用回调函数
- 回调函数的参数只可以有一个:表示的就是该回调函数的调用者(任务对象)
- 使用回调函数的参数调用result()返回的就是任务对象表示的特殊函数return的结果
- 事件循环对象
- 对象。
- 作用:
- 可以将多个任务对象注册/装载到事件循环对象中
- 如果开启了事件循环后,则其内部注册/装载的任务对象表示的指定 *** 作就会被基于异步的被执行
- 创建方式:
- loop = asyncio.get_event_loop()
- 注册且启动方式:
- loop.run_until_complete(task)
- wait方法的作用:
- 将任务列表中的任务对象赋予可被挂起的权限。只有任务对象被赋予了可被挂起的权限后,该
任务对象才可以被挂起
- 挂起:将当前的任务对象交出cpu的使用权。
- 注意事项【重要】:
- 在特殊函数内部不可以出现不支持异步模块对应的代码,否则会中断整个异步效果
- await关键字
- 在特殊函数内部,凡是阻塞 *** 作前都必须使用await进行修饰。await就可以保证
阻塞 *** 作在异步执行的过程中不会被跳过!
- aiohttp
- 是一个支持异步的网络请求模块。
- pip install aiohttp
- 使用代码:
- 1.写出一个大致的架构
async def get_request(url):
#实例化好了一个请求对象
with aiohttp.ClientSession() as sess:
#调用get发起请求,返回一个响应对象
#get/post(url,headers,params/data,proxy="http://ip:port")
with sess.get(url=url) as response:
#获取了字符串形式的响应数据
page_text = response.text()
return page_text
- 2.补充细节
- 在阻塞 *** 作前加上await关键字
- 在每一个with前加上async关键字
- 完整代码:
async def get_request(url):
#实例化好了一个请求对象
with aiohttp.ClientSession() as sess:
#调用get发起请求,返回一个响应对象
#get/post(url,headers,params/data,proxy="http://ip:port")
with await sess.get(url=url) as response:
#text()获取了字符串形式的响应数据
#read()获取byte类型的响应数据
page_text = await response.text()
return page_text
- 多任务爬虫的数据解析
- 一定要使用任务对象的回调函数实现数据解析
- why:
- 多任务的架构中数据的爬取是封装在特殊函数中,我们一定要保证数据请求结束后,
在实现数据解析。
- 使用多任务的异步协程爬取数据实现套路:
- 可以先使用requests模块将待请求数据对应的url封装到有个列表中(同步)
- 可以使用aiohttp模式将列表中的url进行异步的请求和数据解析(异步)
import requests import asyncio import time import aiohttp from lxml import etree urls = [ 'cc', 'bb', 'aa' ] # async def get_request(url): # #requests是一个不支持异步的模块 # page_text = requests.get(url).text # return page_text async def get_request(url): #实例化好了一个请求对象 async with aiohttp.ClientSession() as sess: #调用get发起请求,返回一个响应对象 #get/post(url,headers,params/data,proxy="http://ip:port") async with await sess.get(url=url) as response: #text()获取了字符串形式的响应数据 #read()获取byte类型的响应数据 page_text = await response.text() return page_text #解析函数的封装 def parse(t): #获取请求到页面源码数据 page_text = t.result() tree = etree.HTML(page_text) parse_text = tree.xpath('//a[@id="feng"]/text()')[0] print(parse_text) if __name__ == "__main__": start = time.time() tasks = [] # 多任务列表 # 创建协程对象 for url in urls: c = get_request(url) # 创建一个协程对象 # 创建任务对象 task = asyncio.ensure_future(c) # 任务对象就是对协程对象的进一步封装 task.add_done_callback(parse) # 给task绑定一个回调函数 tasks.append(task) loop = asyncio.get_event_loop() # 创建事件循环对象 # 必须使用wait方法对tasks进行封装才可 loop.run_until_complete(asyncio.wait(tasks)) 3 将任务对象注册到事件循环中且开启事件循环 print('总耗时:',time.time()-start)
# pip install aiohttp import aiohttp # 使用该模块中的ClientSession import asyncio header={ 'User-agent':'aaaaa' } async def test_header(): async with aiohttp.ClientSession(headers=header,cookies={'token':'123sd'}) as session: async with session.get('url',params={'name':'bjsxt'},proxy='http://name:pwd@ip:port') as resp: # text() 返回字符串形式的相应数据 # read() 返回的二进制形式的响应数据 # json() 返回的就是json对象 rs = await resp.text() print(rs)
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)