小爬爬4.协程基本用法&&多任务异步协程爬虫示例(大数据量)
1.测试学习
(2)单线程:
from time import sleep
import time
def request(url):
print('正在请求:',url)
sleep()
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()
print('下载成功:', url)
urls = ['www.baidu.com','www.sogou.com','www.goubanjia.com']
start = time.time()
pool=Pool()
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:: 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/.协程基础.py:>>
正在请求: www.baidu.com
下载成功: www.baidu.com
<Task finished coro=<requests() done, defined at F:/Python_workspace_S18/papa_part/day4/.协程基础.py:> 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()
await asyncio.sleep() #可以用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() #耗时两秒
return 'Hello bobo' @app.route('/jay')
def index_jay():
time.sleep()
return 'Hello jay' @app.route('/tom')
def index_tom():
time.sleep()
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): #回调函数
#.获取响应数据
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,这个参数注意一下,还有代理还是有区别的,复数变成了单数
音频,视频,占用的视频比较大,可以用这个,一般是不用的.
小爬爬4.协程基本用法&&多任务异步协程爬虫示例(大数据量)的更多相关文章
- python爬虫--多任务异步协程, 快点,在快点......
多任务异步协程asyncio 特殊函数: - 就是async关键字修饰的一个函数的定义 - 特殊之处: - 特殊函数被调用后会返回一个协程对象 - 特殊函数调用后内部的程序语句没有被立即执行 - 协程 ...
- [Sw] 使用 Swoole Server task/协程 处理大数据量异步任务时注意
关于 Buffered Query 和 Unbuffered Query:http://www.php.net/manual/zh/mysqlinfo.concepts.buffering.php 对 ...
- 哈,我自己翻译的小书,马上就完成了,是讲用python处理大数据框架hadoop,spark的
花了一些时间, 但感觉很值得. Big Data, MapReduce, Hadoop, and Spark with Python Master Big Data Analytics and Dat ...
- python爬虫---单线程+多任务的异步协程,selenium爬虫模块的使用
python爬虫---单线程+多任务的异步协程,selenium爬虫模块的使用 一丶单线程+多任务的异步协程 特殊函数 # 如果一个函数的定义被async修饰后,则该函数就是一个特殊的函数 async ...
- asyncio模块实现单线程-多任务的异步协程
本篇介绍基于asyncio模块,实现单线程-多任务的异步协程 基本概念 协程函数 协程函数: 定义形式为 async def 的函数; aysnc 在Python3.5+版本新增了aysnc和awai ...
- 小爬爬5:重点回顾&&移动端数据爬取1
1. ()什么是selenium - 基于浏览器自动化的一个模块 ()在爬虫中为什么使用selenium及其和爬虫之间的关联 - 可以便捷的获取动态加载的数据 - 实现模拟登陆 ()列举常见的sele ...
- 深入理解协程(二):yield from实现异步协程
原创不易,转载请联系作者 深入理解协程分为三部分进行讲解: 协程的引入 yield from实现异步协程 async/await实现异步协程 本篇为深入理解协程系列文章的第二篇. yield from ...
- 深入理解协程(三):async/await实现异步协程
原创不易,转载请联系作者 深入理解协程分为三部分进行讲解: 协程的引入 yield from实现异步协程 async/await实现异步协程 本篇为深入理解协程系列文章的最后一篇. 从本篇你将了解到: ...
- 爬虫必知必会(4)_异步协程-selenium_模拟登陆
一.单线程+多任务异步协程(推荐) 协程:对象.可以把协程当做是一个特殊的函数.如果一个函数的定义被async关键字所修饰.该特殊的函数被调用后函数内部的程序语句不会被立即执行,而是会返回一个协程对象 ...
随机推荐
- 2016年省赛 G Triple Nim
2016年省赛 G Triple Nimnim游戏,要求开始局面为先手必败,也就是异或和为0.如果n为奇数,二进制下最后一位只有两种可能1,1,1和1,0,0,显然异或和为1,所以方案数为0如果n为偶 ...
- pc端拖拽
var move=document.getElementsByClassName("page1_2")[0]; var startX=0; var startY=0; var x= ...
- 微信小程序示例
http://www.cnblogs.com/ihardcoder/p/6097941.html http://www.wxapp-union.com/ http://blog.csdn.net/li ...
- 前端插件--swipe.js
swipe.js的作用: 这是一个轻量级的移动滑动组件,支持触摸移动,支持响应式页面. 效果图: 代码: <!DOCTYPE html> <html lang="en&qu ...
- 使用jquery封装一个可以复用的提示框
首先在html中 <div class="backcap"> <div class="diolag"> <div class=&q ...
- $\mathcal{Miemeng}$的病态码风计划
晚上困的要命,先写个码风计划提提神. 计划目标 抵制无理压行. 抵制不可读代码. 倡导代码艺术化,分层化 具体的一些细节和展示 1>整体 首先要把预读部分(我这么叫的),命名域使用,全局变量定义 ...
- GIT → 01:学习版本控制的原因
1.1 没有版本控制出现的问题 备份多个版本,浪费存储空间,花费时间长. 难以恢复至以前的历史版本,容易引发BUG,解决代码冲突困难. 难于追溯问题代码的修改人和修改时间.修改内容.日志信息. 项目升 ...
- 学习JDK1.8集合源码之--ArrayDeque
1. ArrayDeque简介 ArrayDeque是基于数组实现的一种双端队列,既可以当成普通的队列用(先进先出),也可以当成栈来用(后进先出),故ArrayDeque完全可以代替Stack,Arr ...
- dede list调用 内容模型 附件
当我们在list列表页调用内容模型的附件时,会调用出来一个表,数据被包含在表格里面 下面修改这个表格 找到 templets>system>channel_addon.htm文件 < ...
- HDU 4280 Island Transport(dinic+当前弧优化)
Island Transport Description In the vast waters far far away, there are many islands. People are liv ...