python异步爬虫_高性能的异步爬虫

三种方式:

1.多进程多线程(不建议)

2.进程池或者线程池(适当)

3.单线程+异步协程(推荐)

多进程多线程

占用cpu资源,不建议使用

基于线程池的异步爬虫

from multiprocessing.dummy importPoolimporttimedefrequest(url):print('downloading...')

time.sleep(2)print('download!!!')

pool= Pool(3) #线程池

urls =['www.baidu.com','www.sogou.com','www.taobao.com']

start=time.time()

pool.map(request,urls)print('total times:',time.time()-start)

结果:

downloading...

downloading...

downloading...

download!!!

download!!!

download!!!

total times:2.0691184997558594

单线程+异步协程

-event_loop: 事件循环,相当于一个无限循环,我们可以把一些特殊的函数注册到事件循环中,当满足某些条件时,函数就会被执行.在编写异步程序时,必然有部分程序的耗时是比较久的,需要先让出当前程序的控制权,让其在背后运行,让后面的程序先运行起来.当背后运行的程序完成后,再通知主程序进行下一步操作.-coroutine: 中文翻译叫协程.在Python中常代指为协程对象类型.使用async关键字修饰一个普通函数,这个函数在调用时就不会立即执行,而是返回一个协程对象.我们就可以将协程对象(特殊函数)注册到事件循环中.-task: 任务,是对协程对象的进一步封装,包含了任务的各个状态.-future: 和task没有本质区别,创建方法不一样而已.- 另外我们还需要了解 async/await 关键字,它是从 Python 3.5 才出现的,专门用于定义协程。其中,async 定义一个协程,await 用来挂起阻塞方法的执行。

基本使用

importasyncio

asyncdefhello(name):print('hello to :',name)#获取了一个协程对象

c = hello('bobo')#创建一个事件循环对象

loop =asyncio.get_event_loop()#将协程对象注册到事件循环中,然后启动事件循环对象

loop.run_until_complete(c)

执行结果:

hello to : bobo

task的使用

importasyncio

asyncdefhello(name):print('hello to :',name)

c= hello('bobo')

loop=asyncio.get_event_loop()#就协程进行进一步的封装,封装到了task对象中

task = loop.create_task(c) #基于事件循环对象实现

print(task)

loop.run_until_complete(task)print(task)

执行结果::3>>hello to : bobo:3> result=None>

future的使用

importasyncio

asyncdefhello(name):print('hello to :',name)

c= hello('bobo')

task=asyncio.ensure_future(c)

loop=asyncio.get_event_loop()

loop.run_until_complete(task)

绑定回调

defcallback(task):print('i am callback:',task.result())importasyncio

asyncdefhello(name):print('hello to :',name)returnname

c= hello('bobo')

task=asyncio.ensure_future(c)#给任务对象绑定一个回调函数

task.add_done_callback(callback)

loop.run_until_complete(task)

执行结果:

hello to : bobo

i am callback: bobo

多任务异步协程

importasyncio

asyncdefrequest(url):print('正在下载:',url)

sleep(2) #非异步模块的代码:在此处如果存在非异步操作代码,则会彻底让asyncio失去异步的效果

print('下载成功:',url)

urls=['www.baidu.com','www.taobao.com','www.sogou.com']

start=time.time()

loop=asyncio.get_event_loop()

tasks= [] #任务列表,放置多个任务对象

for url inurls:

c=request(url)

task=asyncio.ensure_future(c)

tasks.append(task)#将多个任务对象对应的列表注册到事件循环中

loop.run_until_complete(asyncio.wait(tasks))print('总耗时:',time.time()-start)

执行结果:

正在下载: www.baidu.com

下载成功: www.baidu.com

正在下载: www.taobao.com

下载成功: www.taobao.com

正在下载: www.sogou.com

下载成功: www.sogou.com

总耗时:6.001343250274658

结果发现,并没有实现异步,是因为 time.sleep() 是非异步模块的代码,在协程对象中存在非异步操作代码,则会彻底让asyncio失去异步的效果

asyncio中也有sleep()方法,这个是异步的

importasyncio

asyncdefrequest(url):print('正在下载:',url)

await asyncio.sleep(2)print('下载成功:',url)

urls=['www.baidu.com','www.taobao.com','www.sogou.com']

start=time.time()

loop=asyncio.get_event_loop()

tasks= [] #任务列表,放置多个任务对象

for url inurls:

c=request(url)

task=asyncio.ensure_future(c)

tasks.append(task)#将多个任务对象对应的列表注册到事件循环中

loop.run_until_complete(asyncio.wait(tasks))print('总耗时:',time.time()-start)

执行结果:

正在下载: www.baidu.com

正在下载: www.taobao.com

正在下载: www.sogou.com

下载成功: www.baidu.com

下载成功: www.taobao.com

下载成功: www.sogou.com

总耗时:2.0011146068573 #生效了

多任务异步操作应用到爬虫中

因为影响爬虫效率的因素有很多,所以为了避免网速等因素的影响,单单测试多任务异步的效果,这里我们自己搭建一个服务器.

服务器端:

importrequests

asyncdefget_page(url):print('正在下载:',url)#之所以没有实现异步操作,原因是因为requests模块是一个非异步的模块

response = requests.get(url=url)print('响应数据:',response.text)print('下载成功:',url)

start=time.time()

urls=['http://127.0.0.1:5000/jack','http://127.0.0.1:5000/jay','http://127.0.0.1:5000/tom']

tasks=[]

loop=asyncio.get_event_loop()for url inurls:

c=get_page(url)

task=asyncio.ensure_future(c)

tasks.append(task)

loop.run_until_complete(asyncio.wait(tasks))print('总耗时:',time.time()-start)

执行结果:

正在下载: http://127.0.0.1:5000/bobo

响应数据: Hello bobo

下载成功: http://127.0.0.1:5000/bobo

正在下载: http://127.0.0.1:5000/jay

响应数据: Hello jay

下载成功: http://127.0.0.1:5000/jay

正在下载: http://127.0.0.1:5000/tom

响应数据: Hello tom

下载成功: http://127.0.0.1:5000/tom

总耗时:6.0263447761535645 #无效,原因是因为requests模块是一个非异步的模块

这个时候就要使用另外一个支持异步的网络请求模块了:aiohttp

importaiohttpimportasyncio

asyncdefget_page(url):

async with aiohttp.ClientSession() as session:

async with await session.get(url=url) as response:

page_text= await response.text() #read() json()

print(page_text)

start=time.time()

urls=['http://127.0.0.1:5000/jack','http://127.0.0.1:5000/jay','http://127.0.0.1:5000/tom','http://127.0.0.1:5000/jack','http://127.0.0.1:5000/jay','http://127.0.0.1:5000/tom','http://127.0.0.1:5000/jack','http://127.0.0.1:5000/jay','http://127.0.0.1:5000/tom']

tasks=[]

loop=asyncio.get_event_loop()for url inurls:

c=get_page(url)

task=asyncio.ensure_future(c)

tasks.append(task)

loop.run_until_complete(asyncio.wait(tasks))print('总耗时:',time.time()-start)

执行结果:

Hello jack

Hello jay

Hello tom

Hello jay

Hello jack

Hello tom

Hello jack

Hello tom

Hello jay

总耗时:2.031116008758545

如何实现数据解析--任务的绑定回调机制

importaiohttpimportasyncio#回调函数:解析响应数据

defcallback(task):print('this is callback()')#获取响应数据

page_text =task.result()print('在回调函数中,实现数据解析')

asyncdefget_page(url):

async with aiohttp.ClientSession() as session:

async with await session.get(url=url) as response:

page_text= await response.text() #read() json()

returnpage_text

start=time.time()

urls=['http://127.0.0.1:5000/jack','http://127.0.0.1:5000/jay','http://127.0.0.1:5000/tom','http://127.0.0.1:5000/jack','http://127.0.0.1:5000/jay','http://127.0.0.1:5000/tom','http://127.0.0.1:5000/jack','http://127.0.0.1:5000/jay','http://127.0.0.1:5000/tom']

tasks=[]

loop=asyncio.get_event_loop()for url inurls:

c=get_page(url)

task=asyncio.ensure_future(c)#给任务对象绑定回调函数用于解析响应数据

task.add_done_callback(callback)

tasks.append(task)

loop.run_until_complete(asyncio.wait(tasks))print('总耗时:',time.time()-start)

执行结果:

thisiscallback()

在回调函数中,实现数据解析

thisiscallback()

在回调函数中,实现数据解析

thisiscallback()

在回调函数中,实现数据解析

thisiscallback()

在回调函数中,实现数据解析

thisiscallback()

在回调函数中,实现数据解析

thisiscallback()

在回调函数中,实现数据解析

thisiscallback()

在回调函数中,实现数据解析

thisiscallback()

在回调函数中,实现数据解析

thisiscallback()

在回调函数中,实现数据解析

总耗时:2.018115758895874

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值