标签:ons 语句 let parse 线程池 python on() 通过 byte
import requests
import time
from multiprocessing.dummy import Pool
urls = [ "http://127.0.0.1:5000/zhou1",
"http://127.0.0.1:5000/zhou2",
"http://127.0.0.1:5000/zhou3"]
def get_request(url):
response = requests.get(url).text
return len(response)
if __name__ == ‘__main__‘:
start = time.time()
pool = Pool(3) #线程的数量
#使用get_request作为回调函数,需要基于异步的形式对urls列表中的每一个列表元素进行操作
#保证回调函数必须要有一个参数和返回值
result_list = pool.map(get_reuqest,urls) #(参数是执行的函数名,可迭代对象)
pool.close()#关闭线程池,不再接受新的进程
pool.join()#主线程阻塞等待子线程的退出
print(result_list)
print(time.time()-start)
补充:map方法是阻塞的方法。就是等待子线程都结束之后。主线程在结束
#结果:[1002, 1002, 1002]
2.1248600482940674 异步运行。所以是2秒,如果是同步运行那就是6S了
概念部分
特殊的函数
- 如果一个函数的定义被async修饰后,则该函数就变成了一个特殊的函数
- 特殊之处:
- 该特殊的函数调用后,函数内部的实现语句不会被立即执行
- 该特殊函数被调用后会返回一个协程对象
- 协程对象
- 对象。通过特殊函数的调用返回一个协程对象。
- 协程 == 特殊函数 == 一组指定的操作
- 协程 == 一组指定的操作
- 任务对象
- 任务对象就是一个高级的协程对象。(任务对象就是对协程对象的进一步封装)
- 任务 == 协程 == 特殊函数 == 一组指定操作
- 任务 == 一组指定的操作
- 如何创建一个任务对象:
- asyncio.ensure_future(协程对象)
- 任务对象的高级之处:
- 可以给任务对象绑定回调:
- task.add_done_callback(task_callback)
- 回调函数的调用时机:
- 任务被执行结束后,才可以调用回调函数
- 回调函数的参数只可以有一个:表示的就是该回调函数的调用者(任务对象)
- 使用回调函数的参数调用result()返回的就是任务对象表示的特殊函数return的结果
- 事件循环对象
- 对象。
- 作用:
- 可以将多个任务对象注册/装载到事件循环对象中
- 如果开启了事件循环后,则其内部注册/装载的任务对象表示的指定操作就会被基于异步的被执行
- 创建方式:
- loop = asyncio.get_event_loop()
- 注册且启动方式:
- loop.run_until_complete(task)
代码部分
import asyncio
import requests
import time
async def get_request(url):
print(‘正在请求的url:‘,url)
time.sleep(2)
print(‘请求结束:‘,url)
return ‘bobo‘
#回调函数的封装
#参数t是该回调函数的调用者(任务对象)
def task_callback(t):
print(‘i am task_callback(),参数t:‘,t)
#result返回的就是特殊函数的返回值
print("t.result()返回的是:",t.result()) #因为是回调函数所以能够获取特殊函数的返回结果,就是return值
#以下是使用了asyncio.ensure_future方法
if __name__=="__main__":
#coroutine是一个协程对象
coroutine = get_request(“www.baidu.com”)
#任务对象就是对协程对象的进一步封装
task = asyncio.ensure_future(coroutine)
#给task绑定一个回调函数
task.add_done_callback(task_callback)
#创建事件循环对象
loop = asyncio.get_event_loop()
#将任务对象注册到事件循环中并且开启事件循环
loop.run_until_complete(task)
#使用create_task方法类似,效果是一样的写法不一样
if __name__=="__main__":
#coroutine是一个协程对象
coroutine = get_request(“www.baidu.com”)
#创建事件循环对象
loop = asyncio.get_event_loop() #需要先创建loop循环对象
#任务对象就是对协程对象的进一步封装
task = loop.create_task(coroutine) #不同之处,loop调用的create_task方法来创建任务
#给task绑定一个回调函数
task.add_done_callback(task_callback) #将回调函数名传进去
#将任务对象注册到事件循环中并且开启事件循环
loop.run_until_complete(task)
#结果:
正在请求的url: www.baidu.com
请求结束: www.baidu.com
i am task_callback(),参数t: <Task finished coro=<get_request() done, defined at E:/爬虫练习/test/xxx.py:7> result=‘bobo‘>
t.result()返回的是: bobo
import time
import requests
# async def get_request(url):
# print(‘正在请求的url:‘,url)
# time.sleep(2) #出现了不支持异步模块的代码 这就会导致无法异步操作
# print(‘请求结束:‘,url)
# return ‘bobo‘
async def get_request(url):
print(‘正在请求的url:‘,url)
await asyncio.sleep(2) #支持异步模块的代码
print(‘请求结束:‘,url)
return ‘bobo‘
urls = [
‘www.1.com‘,
‘www.2.com‘,
‘www.3.com‘
]
if __name__ == "__main__":
start = time.time()
tasks = [] #多任务列表
#1.创建协程对象
for url in urls:
c = get_request(url)
#2.创建任务对象
task = asyncio.ensure_future(c)
tasks.append(task)
#3.创建事件循环对象
loop = asyncio.get_event_loop()
# loop.run_until_complete(tasks)
#必须使用wait方法对tasks进行封装才可
loop.run_until_complete(asyncio.wait(tasks))
print(‘总耗时:‘,time.time()-start)
#补充
wait方法的作用:
- 将任务列表中的任务对象赋予可被挂起的权限。只有任务对象被赋予了可被挂起的权限后,该
任务对象才可以被挂起
- 挂起:将当前的任务对象交出cpu的使用权。
- 注意事项【重要】:
- 在特殊函数内部不可以出现不支持异步模块对应的代码,否则会中断整个异步效果
结果:
正在请求的url: www.3.com
正在请求的url: www.2.com
请求结束: www.1.com
请求结束: www.3.com
请求结束: www.2.com
总耗时: 2.0018727779388428
import asyncio
import time
import aiohttp
from lxml import etree
urls = [
‘http://localhost:5000/bobo‘,
‘http://localhost:5000/tom‘,
‘http://localhost:5000/jay‘
]
# async def get_request(url):
# #requests是一个不支持异步的模块,所以无法实现异步请求,用aiohttp代替
# page_text = requests.get(url).text
# return page_text
async def get_request(url):
#实例化好一个请求对象
async with aiohttp.ClientSession() as sess:
#调用get发起请求,返回一个响应对象
async with await sess.get(url=url) as response:
#text()获取字符串形式的响应数据
#read()获取byte类型的响应数据
#json()获取json类型数据
page_text = await response.text() #不管什么类型数据,都要加await
return page_text
#解析函数的封装
def parse(t):
#获取请求的页面源码数据
tree = etree.HTML(t.result)
pare_text = tree.xpath(‘//a[@id="feng"]/text()‘)[0]
#如果需要读写文件。正常写入即可
return pare_text
if __name__ == "__main__":
start = time.time()
tasks=[]
for url in urls:
coroutine = get_request(url)
task = syncio.ensure_future(coroutine)
task.add_done_callback(parse)
tasks.appende(task)
loop = syncio.get_event_loop()
loop.run_until_complete(asyncio.wait(tasks))
print(‘总耗时:‘,time.time()-start)
- 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进行异步的请求和数据解析(异步)
标签:ons 语句 let parse 线程池 python on() 通过 byte
原文地址:https://www.cnblogs.com/zzsy/p/12687882.html