python爬虫-异步爬虫

   日期:2024-12-28    作者:kelihua8888 移动:http://mip.riyuangf.com/mobile/quote/78442.html

:本文章为学习过程中对知识点的记录,供自己复习使用,也给大家做个参考,如有错误,麻烦指出,大家共同探讨,互相进步。
借鉴出处
该文章的路线和主要内容:崔庆才(第2版)python3网络爬虫开发实战

python爬虫-异步爬虫

前言:爬虫属于IO密集型任务,例如使用request库来爬取某个站点,当发出一个请求后,程序必须等待网站返回响应,才能接着运行,而在等待响应的过程中,整个爬虫程序是一直在等待的,实际上没有做任何事情。

1.1 基础知识

  • 阻塞
    阻塞状态指程序未得到所需计算资源时被挂起的状态。程序在等待某个操作完成期间,自身无法继续干别的事情,则称该程序在操作上是阻塞的。
  • 非阻塞
    程序在等待某操作的过程中,自身不被阻塞,可以继续干别的事情,则称该程序在该操作上是非阻塞的。
    非阻塞并不是在任何程序级别、任何情况下都存在的。仅当程序封装的级别可以囊括独立的子程序单元时,程序才可能存在非阻塞状态。
    非阻塞因阻塞的存在而存在,正因为阻塞导致程序运行的耗时增加与效率低下,我们才要把它变成非阻塞的。
  • 同步
    不同程序单元为了共同完成某个任务,在执行过程中需要靠某种通信方式保持协调一致,此时这些程序单元是同步执行的。
    例如在购物系统中更新商品库存时,需要用“行锁”作为通信信号,强制让不同的更新请求排队并按顺序执行,这里的更新库存操作就是同步的。
  • 异步
    为了完成某个任务,有时不同程序单元之间无须通信协调也能完成任务,此时不相关的程序单元之间可以是异步的。
  • 多进程
    多进程就是利用CPU多核的优势,在同一时间并执行多个任务,可以大大提高执行效率。
  • 协程
    协程(coroutine,又称作微线程、纤程,是一种运行在用户态的轻量级线程。
    协程拥有自己的寄存器上下文和栈。协程在调度切换时,将寄存器上下文和栈保存到其他地方,等切换回来的时候,再恢复先前保存的寄存器上下文和栈。因此,协程能保留上一次调用时的状态。
    协程本质上是个单进程,相对于多进程,它没有线程上下文切换的开销,没有原子操作锁定及同步的开销,编程模型也非常简单。

1.2 协程的用法

Python中使用协程最常用的库为asyncio。

  • event_loop:事件循环,相当于一个无限虚幻,我们可以把一些函数注册到这个事情循环上,当满足发生条件时,就调用对应的处理方法。
  • coroutine:中文翻译叫协程,在Python中常指代协程对象类型,我们可以将协程对象注册到时间循环中,它会被事件训话调用。我们可以使用async关键字来定义一个方法,这个方法在调用时不会立即被执行,而是会返回一个协程对象。
  • task:任务,这是对协程对昂的进一步封装,包含协程对象的各个状态。
  • future:代表将来执行或者没有执行的任务的结果,实际上和task没有本质区别。
1.2.1 定义协程

例子1:了解协程对象、事件循环
输入

 

输出

 

例子2:了解task任务

 

输出

 

创建任务的另一种方式:

 
1.2.2 绑定回调

绑定回调的作用就是当协程对象执行完毕之后,就去执行声明的回调函数。
输入

 

输出

 

分析:实际上,即使不适用回调方法,在task运行完毕之后,也可以直接调用result方法获取结果。

1.2.2 多任务协程

执行多次请求,可以定义一个task列表,然后使用asyncio包中的wait方法执行。
输入

 

输出

 

分析
loop函数不要放在定义函数内,否则会报错。

await后面的对象必须是如下格式之一
1、一个原生协程对象
2、一个由types.coroutine修饰的生成器,这个生成器可以返回协程对象
3、由一个包含__await__方法的对象返回的一个迭代器。

上面声明的方式比较复杂,aiohttp是一个支持异步请求的库,它和asyncio配合使用,可以非常方便地实现异步请求操作。

安装

2.1 以一个例子开始aiohttp

输入

 

输入

 

分析:时间循环会运行第一个task,执行第一个get方法时,会被挂起,但get方法第一步是创建了ClientSession对象,是非阻塞的,挂起后会被立马唤醒。接着执行await session.get是会被挂起等待,此期间事件循环会寻找当前未被挂起的协程继续进行。都被挂起后,请求还没有响应,就继续等待直到获取到结果。

2.2 基本介绍

  asynic模块内部实现了对TCP、UDP、SSL协议的异步操作,但是对于HTTP请求来说,就需要用aiohttp实现了。
  aiphttp是一个基于asynico的异步HTTP网络模块,它既提供了服务端,有提供了客户端。其中,我们用服务器可以搭建一个支持异步处理的处理器,这个服务器就是用来处理请求并返回响应的,类似于Django、Flask等一些Web服务器。而客户端可以用来发送请求,类似于使用requests发起一个HTTP请求然后获得响应,但requests发起的是通的网络请求,aiohttp则是异步的
输入
aiohttp客户端例子

 

输出

 

分析

  aiohttp实现的异步爬取,与之前的定义有明显的区别,主要包括以下几点

  • aiohttp是对http请求进行异步爬取的库,实现异步爬取,需要启动协程,而协程则需要借助asynico里面的事件循环才能执行。
  • 每个异步方法的前面都要统一+async来修饰。(async定义的方法会变成一个无法直接执行的协程对象,必须将此对象注册到事件循环中才可以执行
  • with as前面加上async代表声明一个支持异步的上下文管理器。(with as能够自动分配和释放资源
  • 对于一些返回协程对象的操作,官方API文档里,response.text返回的是client对象,所以要在前面加上await;response.status返回的是数值,因此前面不要加await。参考官方文档https://docs.aiohttp.org/en/stable/client_reference.html
  • 最后定义的协程对象要调用事件循环。

2.3 URL参数设置

 

响应,与requests响应基本一致。需要加await的要查看响应类型是否是协程对象(如async修饰的方法,具体查看apihttp的API官方文档。

设置超时

 

ClientTimeout对象还有其他connect、socket_connect等参数,详细API可以参考官方文档:https://docs.aiohttp.org/en/stable/client_quickstart.html#timeouts

并发限制
  由于aiohttp可以支持非常高的并发量,百万量都是能做到的,所以部分网站如果响应不过来,有瞬间将目标网站爬挂掉的危,这是就要限制爬取的并发量。
  一般情况下,借助asynico的Semaphore来控制并发量

 

分析
asyncio.await && asyncio.gather
相同:从功能上看,asyncio.wait 和 asyncio.gather 实现的效果是相同的,都是把所有 Task 任务结果收集起来。
不同:asyncio.wait 会返回两个值:done 和 pending,done 为已完成的协程 Task,pending 为超时未完成的协程 Task,需通过 future.result 调用 Task 的 result;而asyncio.gather 返回的是所有已完成 Task 的 result,不需要再进行调用或其他操作,就可以得到全部结果。

爬取目标
1、爬取地址:https://spa5.scrape.center/
2、使用aiohttp爬取全站的图书数据
3、将数据存储到数据库或独立文件中


特别提示:本信息由相关用户自行提供,真实性未证实,仅供参考。请谨慎采用,风险自负。


举报收藏 0评论 0
0相关评论
相关最新动态
推荐最新动态
点击排行
{
网站首页  |  关于我们  |  联系方式  |  使用协议  |  隐私政策  |  版权隐私  |  网站地图  |  排名推广  |  广告服务  |  积分换礼  |  网站留言  |  RSS订阅  |  违规举报  |  鄂ICP备2020018471号