Python爬虫之协程

何为协程,协程就是当程序遇见了IO(输入,输出)操作时,可以选择性的切换到其他任务上,在微观上它就是一个任务一个任务的切换(切换条件一般就是IO操作),在宏观上,我们看到的就是多任务一起执行。
像下面个例子,是一个单任务同步函数。

import time
def fun():
    print('涂涂傻')
    time.sleep(3)
    print('涂涂真的傻')
if __name__ == '__main__':
    fun()

结果:

涂涂傻
(等三秒)
涂涂真的傻

其中的time.sleep(3)就是让当前线程处于一个长达三秒钟的阻塞,就是此时的cpu不是为我而工作。而协程就是将这阻塞的三秒钟的cpu拿去为其他任务工作,合理利用这休眠的时间。
input()request.get(bilibili)这些,程序都是处于阻塞状态,而一般情况下,当程序进行IO操作时,线程都是会处于阻塞状态。
而上面所讲的都是在单线程下,而异步协程运用于多线程情况下,那么我们接下来说说多任务异步协程。
首先我们需要导入异步协程的模块asyncio,没安装的,先安装哦

import asyncio

然后我们可以创建一个异步协程函数,记住此时就要在def前面加上async,不然你创建的函数就是个正常的函数

async def fun():#async中文意思异步
    print('你好呀,我是涂涂')

此时如果像普通函数那样执行,你会发现得不到结果,因为此时是异步协程函数,执行得到的是一个协程对象

g=fun()
print(g)

运行结果:

<coroutine object fun at 0x000001E6AA805140>

如果我们想要执行这个异步协程函数,那么我们得使用它内置的函数asyncio.run(),这个函数需要asyncio模块的支持。

asyncio.run(g)

运行结果:

你好呀,我是涂涂

既然知道了一个异步协程函数怎么构建了,那么接下来我们就多写几个异步协程函数吧

import asyncio
async def fun1():
    print('你好呀,我叫涂涂')
    await asyncio.sleep(3)  #异步操作的代码
    print('你好呀,我是你爸爸')
async def fun2():
    print('德玛西亚')
    await asyncio.sleep(2)
    print('艾欧里亚')
async  def fun3():
    print('哈哈哈')
    await asyncio.sleep(4)
    print('呜呜呜')

我们用await asyncio.sleep()模拟阻塞情况,就是此时将这个函数挂起,记住这里不要用time.sleep(),因为程序只有遇见await这个关键字就会跳出来,去执行其他程序,但如果是time.sleep()就不会跳出,这样的话是同步,而不是异步了。
然后我们写一个main()函数来运行一下

async def main():
    tasks=[asyncio.create_task(fun1()),
           asyncio.create_task(fun2()),
           asyncio.create_task(fun3())]
    await asyncio.wait(tasks)

就是将三个函数变成了一个任务列表。
在python3.8版本后,需要加上asyncio.create_task()来创建任务,以前的版本可以不需要添加。
运行一下看看

 t1=time.time()
 asyncio.run(main())
 t2=time.time()
 print("耗时:",t2-t1)

运行结果:

你好呀,我叫涂涂
德玛西亚
哈哈哈哈
艾欧里亚
你好呀,我是你爸爸
呜呜呜
耗时:4.005320310592651

然后我们来说说在如何在爬虫上用到异步协程

import asyncio
async def download(url):
    print('准备开始下载')
    await asyncio.sleep(2)#模拟网络请求,get()
    print('下载完成')

async def main():
    urls=[
        'baidu.com','sogou.com','bilibili.com'
    ]
    tasks=[]
    for url in urls:
        d=download(url)
        tasks.append(asyncio.create_task(d))
    await asyncio.wait(tasks)

这就是一个简单的模拟从网上下载的异步协程框架,接下来我们以一个实际的小例子,从网上随便找几张图片下载。
在进行网络请求的时候,我们需要用到另外一个模块aiohttp等价于将requests.get()同步操作———>异步操作aiohttp

import aiohttp
import asyncio

url=['http://kr.shanghai-jiuxin.com/file/bizhi/20211206/oka0yp3aj1t.jpg',
     'http://kr.shanghai-jiuxin.com/file/bizhi/20211201/aesbpiexavr.jpg',
     'http://kr.shanghai-jiuxin.com/file/bizhi/20211201/r0jwwdpfjjp.jpg']

async def download(url):
     #发送请求     s=aiogttp.ClientSession()<==>request
     #得到回应
     #写入内容
     name=url.rsplit('/',1)[1]
     async with aiohttp.ClientSession() as session:#等价于request
          async with session.get(url) as resp:#等价于resp=request.get()
               #请求回来了,写入文件
               #可自己学习使用aiofiles模块
               with open(name,'wb')as f:
                    f.write(await resp.content.read())#读取内容也是io操作,需要await挂起,拿取页面源代码resp.text()
     print(name,'ok')
async def main():
     tasks=[]
     for i in url :
          tasks.append(asyncio.create_task(download(i)))
     await asyncio.wait(tasks)
if __name__ == '__main__':
     loop = asyncio.get_event_loop()
     loop.run_until_complete(main())

如果你使用asyncio.run()会自动关闭循环,并且调用_ProactorBasePipeTransport.__del__报错, 而asyncio.run_until_complete()不会.
运行结果:

oka0yp3aj1t.jpg ok
r0jwwdpfjjp.jpg ok
aesbpiexavr.jpg ok

一个自己用的学习笔记,如有不对,还望大佬予以斧正。

  • 7
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值