1.测试学习
(2)单线程:
from time import sleep import time def request(url): print('正在请求:',url) sleep(2) print('下载成功:', url) urls = ['www.baidu.com','www.sogou.com','www.goubanjia.com'] start = time.time() for url in urls: request(url) print(time.time()-start)
测试结果:需要6秒多
正在请求: www.baidu.com 下载成功: www.baidu.com 正在请求: www.sogou.com 下载成功: www.sogou.com 正在请求: www.goubanjia.com 下载成功: www.goubanjia.com 6.001747369766235
(2)开启线程池:测试结果是2秒多
from time import sleep import time from multiprocessing.dummy import Pool def request(url): print('正在请求:',url) sleep(2) print('下载成功:', url) urls = ['www.baidu.com','www.sogou.com','www.goubanjia.com'] start = time.time() pool=Pool(3) pool.map(request,urls) print(time.time()-start)
测试结果:
正在请求: www.baidu.com 正在请求: www.sogou.com 正在请求: www.goubanjia.com 下载成功: www.goubanjia.com 下载成功: www.sogou.com 下载成功: www.baidu.com 2.034695625305176
(3)在程序中是否可以一味的使用多线程,多进程?
推荐:单线程+异步协程(效率最高,用的人不是很多,大量爬取数据是会用到的)
下面了解一下
协程(go和python独有的概念),,协程不会占用很高的内存
领导在乎的是把数据爬取出来.
主要还是request模块的学习.下面学习几个概念这几个概念,一会儿会在代码中有所体现
event_loop:事件循环,相当于一个无限循环,我们可以把一些特殊函数注册(放置)到这个事件循环上,当满足某些条件的时候,函数就会被循环执行。程序是按照设定的顺序从头执行到尾,
运行的次数也是完全按照设定。当在编写异步程序时,必然其中有部分程序的运行耗时是比较久的,需要先让出当前程序的控制权,让其在背后运行,让另一部分的程序先运行起来。当背后运行的程序完成后,
也需要及时通知主程序已经完成任务可以进行下一步操作,但这个过程所需的时间是不确定的,需要主程序不断的监听状态,一旦收到了任务完成的消息,就开始进行下一步。loop就是这个持续不断的监视器。 coroutine:中文翻译叫协程,在 Python 中常指代为协程对象类型,我们可以将协程对象注册到事件循环中, 它会被事件循环调用。我们可以使用 async 关键字来定义一个方法,这个方法在调用时不会立即被执行, 而是返回一个协程对象。 task:任务对象,它是对协程对象的进一步封装,包含了任务的各个状态。 future:任务对象,代表将来执行或还没有执行的任务,实际上和 task 没有本质区别。 另外我们还需要了解 async/await 关键字,它是从 Python 3.6 才出现的,专门用于定义协程。其中,async 定义一个协程,await 用来挂起阻塞方法的执行。
(4)协程基础
#asyncio是python3.6才出来的一种技术 import asyncio async def requests(url): #被async修饰,就会没有返回值,内部不会执行,只返回一个协程对象 print('正在请求:',url) print('下载成功:',url) c=requests('www.baidu.com') print(c)
得到下面的结果:
<coroutine object requests at 0x000001A6E0150410> sys:1: RuntimeWarning: coroutine 'requests' was never awaited
(5)升级初版
import asyncio async def requests(url): #async本质上是个生成器 print('正在请求:',url) print('下载成功:',url) c=requests('www.baidu.com') #实例化一个事件循环对象 loop=asyncio.get_event_loop() #将协程对象注册到时间循环对象中,并且我们需要启动事件循环对象 loop.run_until_complete(c) #可以无限循环的位置(c...)
得到下面的结果:
正在请求: www.baidu.com
下载成功: www.baidu.com
(6)
import asyncio async def requests(url): #async本质上是个生成器,特殊函数async关键字 print('正在请求:',url) print('下载成功:',url) c=requests('www.baidu.com') #协程 #实例化一个事件循环对象 loop=asyncio.get_event_loop() #添加的新点,任务对象 #方法1:创建一个任务对象,将协程对象封装到了该对象中 task=loop.create_task(c) #这一步是进一步的处理,. #任务对象 #方法2:另一种形式实例化任务对象的方法,不需要上边的实例化事件循环对象 # task=asyncio.ensure_future(c) print(task) #pending #将协程对象注册到事件循环对象中,并且我们需要启动事件循环对象 loop.run_until_complete(task) #括号里边可以有多个参数,无限循环 #事件循环 print(task) #finished #核心:绑定回调
注意:任务对象就是对协程的一种封装
结果:
<Task pending coro=<requests() running at F:/Python_workspace_S18/papa_part/day4/2.协程基础.py:49>> 正在请求: www.baidu.com 下载成功: www.baidu.com <Task finished coro=<requests() done, defined at F:/Python_workspace_S18/papa_part/day4/2.协程基础.py:49> result=None>
(7)给任务对象绑定回调,这个虽然简单但是及其重要
单任务异步协程
#单任务异步协程 import asyncio async def request(url): print('正在请求:', url) print('下载成功:', url) return url #回调函数必须有一个参数:task #task.result():任务对象中封装的协程对象对应的特殊函数内部的返回值 def callbak(task): #必须有一个参数,并且必须是任务本身 print('the callback') print(task.result()) #result就是上边函数的url c = request('www.baidu.com') loop=asyncio.get_event_loop() #给任务对象绑定一个回调函数 task=asyncio.ensure_future(c) #先执行这一步,才能执行回调 task.add_done_callback(callbak) #这个多了一个回调函数 #什么是回调函数?当任务对象执行完成之后,可以回头调用给其绑定的另外一个函数 loop.run_until_complete(task) #全部执行完成之后,才执行回调函数
结果:
正在请求: www.baidu.com
下载成功: www.baidu.com
the callback
www.baidu.com
另一种写法:
#单任务异步协程 import asyncio async def request(url): print('正在请求:', url) print('下载成功:', url) return url #回调函数必须有一个参数:task #task.result():任务对象中封装的协程对象对应的特殊函数内部的返回值 def callbak(task): #必须有一个参数,并且必须是任务本身 print('the callback') print(task.result()) #result就是上边函数的url c = request('www.baidu.com') loop=asyncio.get_event_loop() #给任务对象绑定一个回调函数 # task=asyncio.ensure_future(c) #先执行这一步,才能执行回调 #第一种写法 task=loop.create_task(c) #第二种写法 task.add_done_callback(callbak) #这个多了一个回调函数 #什么是回调函数?当任务对象执行完成之后,可以回头调用给其绑定的另外一个函数 loop.run_until_complete(task) #全部执行完成之后,才执行回调函数
回调函数的目的:对数据进行解析
(8)多任务异步协程:(1个任务不是异步),
只有多任务异步协程才是有意义的
asyncio出现来了async和await
from time import sleep import asyncio import time urls = ['www.baidu.com','www.sogou.com','www.goubanjia.com'] start = time.time() async def request(url): print('正在请求:',url) #在多任务异步协程实现中,不可以出现不支持异步的相关代码。比如time模块中的sleep # sleep(2) await asyncio.sleep(2) #可以用asyncio里边的sleep,才能计算出异步时间,支持异步,并且必须加上await才能等待 print('下载成功:',url) loop = asyncio.get_event_loop() #通过事件循环执行 #任务列表:放置多个任务对象 tasks = [] for url in urls: c = request(url) task = asyncio.ensure_future(c) tasks.append(task) #依次追加到列表中 loop.run_until_complete(asyncio.wait(tasks)) #作用:将任务对象注册到事件当中,只能启动一次的用法 #里边的参数代表的是,多个事件循环必须是异步的因此需要加上asyncio.wait(),有阻塞就挂起,执行完再搞阻塞 print(time.time()-start)
得到下面的结果:
正在请求: www.baidu.com 正在请求: www.sogou.com 正在请求: www.goubanjia.com 下载成功: www.baidu.com 下载成功: www.sogou.com 下载成功: www.goubanjia.com 2.040722608566284
(9)多任务异步协程在flask中的应用
下面是flaskServer.py文件,首先需要安装flask模块
# Author: studybrother sun from flask import Flask import time app = Flask(__name__) @app.route('/bobo') def index_bobo(): time.sleep(2) #耗时两秒 return 'Hello bobo' @app.route('/jay') def index_jay(): time.sleep(2) return 'Hello jay' @app.route('/tom') def index_tom(): time.sleep(2) return 'Hello tom' if __name__ == '__main__': app.run(threaded=True)
启动:服务器上的程序,访问下面的网址,需要等待2s钟才能得到下面的结果
上边的服务器启动之后,我们再次启动下面的程序
import requests #目的是发送请求 import asyncio import time #单线程+多任务异步协程 urls = [ 'http://127.0.0.1:5000/jay', 'http://127.0.0.1:5000/bobo', 'http://127.0.0.1:5000/tom' ] start=time.time() for url in urls: page_text=requests.get(url=url).text #请求url得到的返回值 print(page_text) print(time.time()-start)
得到下面的结果:
Hello jay Hello bobo Hello tom 6.132113456726074
下面是单线程+异步协程在爬虫中的用法:
import requests import asyncio import time #单线程+多任务异步协程 urls = [ 'http://127.0.0.1:5000/jay', 'http://127.0.0.1:5000/bobo', 'http://127.0.0.1:5000/tom' ] async def get_pageText(url): print('正在下载:',url) #requests模块是不支持异步操作的。,下面是6s的原因,不支持异步 page_text = requests.get(url).text print('下载完毕:',url) return page_text start = time.time() tasks = [] for url in urls: c = get_pageText(url) task = asyncio.ensure_future(c) tasks.append(task) loop = asyncio.get_event_loop() loop.run_until_complete(asyncio.wait(tasks)) #这行代码表示注册,以及启动的作用 print(time.time()-start)
得到下面的结果:
正在下载: http://127.0.0.1:5000/jay 下载完毕: http://127.0.0.1:5000/jay 正在下载: http://127.0.0.1:5000/bobo 下载完毕: http://127.0.0.1:5000/bobo 正在下载: http://127.0.0.1:5000/tom 下载完毕: http://127.0.0.1:5000/tom 6.1820220947265625
应该是2s多,怎么会这样????
#aiohttp:支持异步的一个基于网络请求的模块 # pip install aiohttp #安装这个异步请求模块 import requests import asyncio import time import aiohttp #支持异步的网络请求内容,升级支持异步请求的requests模块 #单线程+多任务异步协程 urls = [ 'http://127.0.0.1:5000/jay', 'http://127.0.0.1:5000/bobo', 'http://127.0.0.1:5000/tom' ] #代理操作: #async with await s.get(url,proxy="http://ip:port") as response: async def get_pageText(url): async with aiohttp.ClientSession() as s: #实例化请求对象 async with await s.get(url) as response: #得到相应对象,在异步中有with就需要加上async #发起请求也是需要加上await的 page_text = await response.text() #注意这个地方text是个方法,得到响应数据就需要先挂起 # 借助于回调函数进行响应数据的解析操作await print(page_text) return page_text #封装回调函数用于数据解析 start = time.time() tasks = [] for url in urls: c = get_pageText(url) task = asyncio.ensure_future(c) #给任务对象绑定回调函数用于数据解析 tasks.append(task) loop = asyncio.get_event_loop() loop.run_until_complete(asyncio.wait(tasks)) print(time.time()-start)
已经实现.得到下面的结果:
Hello jay Hello bobo Hello tom 2.1180801391601562
升级:
#aiohttp:支持异步的一个基于网络请求的模块 # pip install aiohttp import requests import asyncio import time import aiohttp #支持异步的网络请求内容,升级支持异步请求的requests模块 #单线程+多任务异步协程 urls = [ 'http://127.0.0.1:5000/jay', 'http://127.0.0.1:5000/bobo', 'http://127.0.0.1:5000/tom' ] #代理操作:写代理时候的区别 #async with await s.get(url,proxy="http://ip:port") as response: async def get_pageText(url): async with aiohttp.ClientSession() as s: #实例化请求对象 async with await s.get(url) as response: #得到相应对象,在异步中有with就需要加上async #发起请求也是需要加上await的 page_text = await response.text() #注意这个地方text是个方法,得到响应数据就需要先挂起 # 借助于回调函数进行响应数据的解析操作await print(page_text) return page_text #封装回调函数用于数据解析 def parse(task): #回调函数 #1.获取响应数据 page_text = task.result() print(page_text+',即将进行数据解析!!!') #解析操作写在该位置 start = time.time() tasks = [] for url in urls: c = get_pageText(url) task = asyncio.ensure_future(c) #给任务对象绑定回调函数用于数据解析 task.add_done_callback(parse) tasks.append(task) loop = asyncio.get_event_loop() loop.run_until_complete(asyncio.wait(tasks)) print(time.time()-start)
下面得到的结果:顺序jay>bobo>tom>
注意:这个是有一定顺序的
Hello jay Hello jay,即将进行数据解析!!! Hello bobo Hello bobo,即将进行数据解析!!! Hello tom Hello tom,即将进行数据解析!!! 2.0991756916046143
get里边是paras,post里边是data,这个参数注意一下,还有代理还是有区别的,复数变成了单数
音频,视频,占用的视频比较大,可以用这个,一般是不用的.