版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
第6章提升网络爬虫速度《Python网络爬虫基础教程》学习目标/Target了解网络爬虫速度的提升方案,能够说出多线程和协程提升爬虫速度的区别熟悉多线程爬虫的运行流程,能够归纳多线程爬虫的运行流程掌握多线程爬虫的实现技术,能够使用threading和queue模块实现多线程爬虫熟悉协程爬虫的运行流程,能够归纳协程爬虫的运行流程掌握协程爬虫的实现技术,能够使用asyncio和aiohttp库实现协程爬虫章节概述/Summary前面章节编写的程序均属于单线程爬虫,其采用顺序采集模式——仅当前网页完成采集后才会启动下一页采集,这种机制在网络环境不稳定时存在显著缺陷:若某一网页因服务器负载过高、网络拥堵或资源加载异常而响应迟缓,网络爬虫会等待网页响应,导致后续所有的采集任务停滞,严重降低运行效率。为突破单线程爬虫的效率瓶颈,可以引入多线程、协程等并发技术,通过并行调度实现多网页数据的同时抓取与解析。本章将围绕此类性能提升方案展开系统探讨。目录/Contents6.16.26.3网络爬虫速度提升方案多线程爬虫协程爬虫6.4实践项目:采集黑马头条的评论列表网路爬虫速度提升方案6.1了解网络爬虫速度的提升方案,能够说出多线程和协程提升爬虫速度的区别学习目标6.1网络爬虫速度提升方案在大数据时代,网络爬虫作为数据采集的核心工具,其运行效率直接影响着数据获取的时效性和应用价值。互联网数据量的爆炸式增长以及业务对实时数据需求的不断提升,传统的单线程爬虫模式正面临严峻挑战,尤其是在面对海量网页抓取、高频数据更新或时效性要求严格的场景时,缓慢的采集速度会导致关键数据获取延迟,造成宝贵数据资源的流失。同时,低效的采集过程还会增加资源消耗和运营成本,降低整体数据价值转化效率。因此,提升网络爬虫的速度是非常有必要的,这不仅是技术优化的需求,更是保障数据驱动业务持续发展的重要基础,对企业的数字化转型和智能化升级具有关键意义。6.1网络爬虫速度提升方案影响网络爬虫速度的因素有哪些?6.1网络爬虫速度提升方案影响网络爬虫速度的因素有很多,其中关键的是网络I/O操作的效率。作为典型的IO密集型任务,爬虫的网络请求过程需要依赖网络协议完成主机间数据传输,而这一过程的速度与CPU的处理速度存在数个数量级的差距。以图片下载为例,当爬虫通过HTTP协议发起请求后,线程会被强制阻塞直至图片数据完全传输完成。在此期间,CPU虽具备每秒处理数百万次指令的能力,却因等待网络响应而处于闲置状态,形成“高算力资源浪费+低任务吞吐量”的矛盾。这种由网络I/O延迟导致的线程阻塞不仅延长了整体任务耗时,更使得硬件资源无法被有效利用,成为制约爬虫速度的根本性瓶颈。6.1网络爬虫速度提升方案前面编写的网络爬虫程序在抓取和解析网页数据时,都是采用同步执行模式,即抓取和解析完一个网页之后再抓取和解析另一个网页,如同接力赛跑中下一棒选手必须等待交接棒才能起跑,效率是非常低的。为了提升网络爬虫的速度,需要将网络爬虫程序的同步执行模式改成异步执行模式,即同时抓取或解析多个网页,如同百米赛跑中所有选手在发令枪响后同时起跑,每个跑道的选手不受其他人的影响。6.1网络爬虫速度提升方案多进程爬虫多线程爬虫协程爬虫多进程爬虫通过创建多个独立进程并行处理抓取任务,每个进程拥有独立的内存空间与CPU资源,可突破单进程的多核利用率限制。其核心原理是利用操作系统的进程调度机制,将不同任务分配至不同CPU核心同时执行,适用于CPU密集的场景。其优势在于进程间隔离性强,某一进程崩溃不影响整体,但进程创建开销较大,且需通过特定通信机制共享数据。6.1网络爬虫速度提升方案在Python中,提升网络爬虫程序运行速度的方案主要有3种,分别是多进程、多线程和协程,具体如下。多进程爬虫多线程爬虫协程爬虫多线程爬虫会在单个进程内创建多个线程以并发执行任务,这些线程共享进程内存资源,通过操作系统的线程调度实现任务切换。对于I/O密集型的网络请求场景,当某一线程因网络延迟阻塞时,操作系统会切换至其他线程继续工作,避免CPU闲置。其原理类似“多车道并行驾驶”,通过线程间的上下文切换增大单位时间内的任务吞吐量,但需要注意线程安全问题(如共享资源竞争)和GIL(GlobalInterpreter,全局解释器锁)对多核CPU的限制。6.1网络爬虫速度提升方案在Python中,提升网络爬虫程序运行速度的方案主要有3种,分别是多进程、多线程和协程,具体如下。多进程爬虫多线程爬虫协程爬虫协程爬虫基于单线程事件循环实现“用户态并发”,无需操作系统介入调度,完全由程序自主控制任务切换。其核心机制是通过非阻塞IO操作实现任务协作:当某个协程发起网络请求时,会主动释放执行权,事件循环随即调度其他协程继续工作,待IO操作完成后再恢复该协程执行。这一过程类似“单人多任务流水线”,单线程可同时管理数万协程任务,每个协程仅占用数KB内存,内存开销极低。这种模式特别适合超大规模URL的高频并发采集,既避免了多线程上下文切换的系统开销,又能在单线程内实现微观层面的任务并行,充分提升IO密集型场景的执行效率。6.1网络爬虫速度提升方案在Python中,提升网络爬虫程序运行速度的方案主要有3种,分别是多进程、多线程和协程,具体如下。6.1网络爬虫速度提升方案网络爬虫如何选择多进程、多线程和协程呢?综上所述,多进程适合CPU密集型场景,如复杂数据解析、加密运算等,但进程创建与通信开销较大;多线程适用于I/O密集型场景,如网络请求、文件读写,但需处理线程安全问题;协程则在超大规模I/O场景中表现优异,通过单线程高并发与非阻塞IO,实现微秒级任务切换,内存开销极低,特别适合高频URL采集。结合多线程、多进程和协程的适用场景,我们一般会选择多线程和协程技术开发网络爬虫程序。6.1网络爬虫速度提升方案多学一招进程是系统资源分配的基本单元,每个进程拥有独立的内存空间,进程间数据相互隔离;线程是系统调度执行的最小单位,依附于进程存在,同一进程内的线程共享内存资源,可通过共享数据快速通信;协程是用户态的轻量级执行单元,由程序自主控制调度,具备独立的寄存器上下文和栈空间,无需操作系统介入即可实现任务切换,内存开销远低于线程。三者构成从系统级资源分配到用户态任务调度的多层次并发体系。进程、线程和协程多线程爬虫6.2熟悉多线程爬虫的运行流程,能够归纳多线程爬虫的运行流程学习目标6.2.1多线程爬虫流程分析6.2.1多线程爬虫流程分析多线程爬虫会将多线程技术运用在抓取网页和解析网页上,它的运行流程图如右所示。6.2.1多线程爬虫流程分析多线程爬虫的运行流程如下。构建一个网址队列,专门用于存放所有待抓取数据的网址。相较于单线程爬虫,多线程爬虫需借助多个线程并行抓取,因此该队列承担着统一管理、有序分配网址任务的关键职责,确保抓取工作有条不紊地开展。1将抓取到的网页源代码及时存入网页源码队列,该队列作为中间缓存区,为后续解析工作提供稳定的数据来源,保证解析线程随时有内容可处理。3开启适量固定数量的线程。每个线程在完成一个网页的数据抓取后,即刻从网址队列中领取新任务,开启下一轮抓取。值得注意的是,线程数量的设置需谨慎权衡,过多易引发线程频繁调度,挤占资源拖慢效率;过少则难以充分释放多线程的并行优势。2启动多个解析线程,对源码队列中的网页数据进行解析,从网页源代码中提取出有价值的信息。4对网页数据队列中的数据进行最后的格式转换、去重等处理后,将其持久化存储至指定数据库或文件中。6将解析处理后的数据暂存至网页数据队列。5掌握多线程爬虫的实现技术,能够使用threading和queue模块实现多线程爬虫学习目标6.2.2多线程爬虫实现技术6.2.2多线程爬虫实现技术由于线程具有独立运行、状态不可预测且执行顺序随机的特性,当多个线程同时访问共享资源时,极易引发资源竞争,导致程序产生不可预期的结果。因此,多线程爬虫通常使用线程安全的队列来管理网址和网页源代码,以此实现线程间的安全协作。Python标准库中提供了专门支持多线程编程的threading模块和队列的queue模块。6.2.2多线程爬虫实现技术threading模块是Python中多线程编程的重要工具,它为开发者提供了一套完整的线程管理机制,使得在程序中实现多线程并发执行变得便捷高效。Thread是该模块提供的核心类,专门用于创建和管理线程实例。通过实例化Thread类,开发者可以轻松创建线程(也称子线程),为其指定执行的目标函数及相关参数,并且能灵活控制线程的启动、暂停、终止等操作。1.threading模块Thread类的构造方法声明如下。6.2.2多线程爬虫实现技术Thread(group=None,target=None,name=None,args=(),kwargs={},*,daemon=None)group:表示线程组,必须设为None。Python未实现线程组功能,仅保留该参数用于兼容旧版本。target:用于指定线程执行的任务函数。name:线程的名称,默认由“Thread-N”形式组成,其中N为递增数字。args:传递给target函数的位置参数。kwargs:传递给target函数的关键字参数。daemon:表示是否将线程设为守护线程(在后台运行的一类特殊线程,用于执行特定的任务)。若将线程设为守护线程,则主线程结束时会自动终止守护线程,否则主线程会等待该线程结束后再退出。默认值为None,表示当前线程会自动继承父线程的守护属性。若父线程是守护线程,则当前线程也会是守护线程,反之则不是。1.threading模块6.2.2多线程爬虫实现技术值得一提的是,主线程是程序启动时自动创建的线程,是所有子线程的父线程,负责协调和管理子线程的执行,其结束通常意味着程序整体运行的终止。1.threading模块6.2.2多线程爬虫实现技术classMyThread(Thread):def__init__(self,num):super().__init__()='线程'+str(num)defrun(self):message=+'运行'print(message)thread_two=MyThread(1)方式二fromthreadingimportThread#任务函数deftask():print('线程运行')thread_one=Thread(target=task)
方式一Python中创建线程的方式。queue模块是Python多线程编程中实现线程安全协作的核心组件,它提供了Queue、LifoQueue和PriorityQueue三种线程安全队列类,通过内部锁机制确保队列操作的原子性,有效解决多线程环境下的资源竞争问题。关于这3个类的介绍如下。6.2.2多线程爬虫实现技术fromqueueimportQueuequeue_object=Queue(10)foriinrange(4):queue_object.put(i)whilenotqueue_object.empty():print(queue_object.get())Queue类Queue类表示一个基本的FIFO(FirstInFirstOut,先进先出)队列,先存入队列中的元素先取出来。2.queue模块6.2.2多线程爬虫实现技术fromqueueimportLifoQueuelifo_queue=LifoQueue()foriinrange(4):lifo_queue.put(i)whilenotlifo_queue.empty():print(lifo_queue.get())LifoQueue类LifoQueue类表示一个LIFO(LastinFirstOut,后进先出)队列,与栈类似,后存入队列中的元素先取出来。以下是使用了LifoQueue类的示例代码。2.queue模块6.2.2多线程爬虫实现技术fromqueueimportPriorityQueueclassJob:def__init__(self,level,description):self.level=levelself.description=descriptionreturndef__lt__(self,other):returnself.level<other.levelpriority_queue=PriorityQueue()priority_queue.put(Job(5,'中级别工作'))priority_queue.put(Job(10,'低级别工作'))priority_queue.put(Job(1,'重要工作'))whilenotpriority_queue.empty():next_job=priority_queue.get()print('开始工作:',next_job.description)(3)PriorityQueue类PriorityQueue类表示优先级队列,它按级别顺序取出元素,级别最低的最先取出。右侧是使用了PriorityQueue类的示例代码。2.queue模块6.2.2多线程爬虫实现技术在上述3个类中,Queue类是LifoQueue和PriorityQueue的父类,它提供了创建队列的构造方法,该方法的声明如下。Queue(maxsize)在上述方法中,maxsize参数表示放入队列元素数量的上限。如果达到上限,再向队列中添加元素则会产生阻塞,直到队列中的一个元素被取出才能添加成功。若maxsize参数的值小于或等于0(默认值),则表明队列的大小没有限制。queue_object=Queue(10)例如在上面的Queue类示例中,创建一个长度为10的队列,具体代码如下。6.2.2多线程爬虫实现技术为了便于管理队列的元素,Queue类中提供了一些常用方法,这些方法的说明如下表所示。方法说明qsize()返回队列的大小empty()判断队列是否为空。如果队列为空,返回True,否则返回Falsefull()判断队列是否已满。如果队列满了,则返回True,否则返回False。注意,该方法仅对设置了最大长度的队列有效get(block=True,timeout=None)从队列中移除并返回一个元素。参数block用于指定是否阻塞调用该方法的线程,默认值为True,表示会阻塞线程直至队列有元素可用;参数timeout用于设置超时时间,超时未获取到元素则抛出Empty异常6.2.2多线程爬虫实现技术为了便于管理队列的元素,Queue类中提供了一些常用方法,这些方法的说明如下表所示。方法说明put(item,block=True,timeout=None)将一个元素放入队列末尾。参数item表示要放入队列的元素;参数block用于指定是否阻塞调用该方法的线程,默认值为True,表示会阻塞线程直至队列有空间可用;参数timeout用于设置超时时间,超时未放入元素则抛出Full异常join()阻塞主线程,直到队列中所有元素都被处理完毕,需配合task_done()使用task_done()用于标记队列任务处理完成。在完成一项任务之后,该方法向队列发送一个“任务已完成”的信号get_nowait()立即取出一个元素,无须额外等待,等价于get(block=False)put_nowait()立即放入一个元素,无须额外等待,等价于put(item,block=False)6.2.2多线程爬虫实现技术例如在前面Queue类的示例代码中,先向队列中插入4个元素,再依次取出4个元素。具体代码如下。foriinrange(4):#向队列中插入元素
queue_object.put(i)whilenotqueue_object.empty():#从队列中取出元素
print(queue_object.get())掌握多线程爬虫的实现技术,能够使用多线程技术抓取黑马程序员论坛网站数据学习目标6.2.3多线程爬虫基本示例6.2.3多线程爬虫基本示例下面以黑马程序员论坛网站为例,演示如何使用threading模块和queue模块实现多线程爬虫,并让多线程爬虫采集Python+人工智能技术交流版块中所有帖子的文章标题、文章作者、文章链接以及发布时间。6.2.3多线程爬虫基本示例导入程序中需要使用的库或模块。01定义HeiMa类,在该类的构造方法中定义分别表示请求头、网址队列、网页源码队列、网页数据队列的4个属性。定义构建请求网址的populate_url()方法。在该方法中使用列表推导式生成需要抓取的URL地址,并将URL地址添加到网址队列中。03定义抓取网页数据process_url_to_html()方法。在该方法中首先使用无限循环从网址队列中逐个取出URL,然后向黑马程序员论坛服务器发送GET请求,接着将服务器返回的响应内容添加到网页源码队列中,最后向网址队列发送完成信号。04定义提取数据的parse_html()方法。在该方法中首先使用无限循环获取网页源码队列中的数据,然后使用XPath路径表达式从网页源代码中提取文章标题、文章链接、文章作者和发布时间,将提取的这些数据放入网页数据队列中,最后向网页源码队列发送完成信号。05定义用于存储数据的save_data()方法。在该方法中首先使用无限循环获取网页数据队列中的数据,将这些数据写入thread-heima.json文件中,然后向网页数据队列发送完成信号。06定义启动多线程爬虫的run()方法。在该方法中分别创建1个生成请求URL的线程、9个抓取网页的线程、9个解析网页线程和1个保存数据线程。07026.2.3多线程爬虫基本示例执行代码运行代码后,可以看到在代码文件同级目录下添加了一个新的文件thread-heima.json,该文件中存储了Python技术交流版块中所有贴子的文章标题、文章作者、文章链接和发布时间。[单击查看源码]熟悉多线程爬虫性能分析,能够计算出多线程爬虫耗时时间学习目标6.2.4多线程爬虫性能分析6.2.4多线程爬虫性能分析在4.6节中,编写了一个单线程爬虫采集Python+人工智能技术交流版块中所有贴子的文章标题、文章作者、文章链接和发布时间。这里以4.6节的项目和6.2.3节的项目为例,分别在这两个项目中增加网络爬虫耗时计算的代码,用于计算单线程爬虫和多线程爬虫在采集相同数据时总共耗费的时间,比较两者之间的性能。6.2.4多线程爬虫性能分析if__name__=="__main__":begin_page=int(input("请输入起始页码:"))end_page=int(input("请输入结束页码:"))s_time=time.time()heima_forum(begin_page,end_page)e_time=time.time()print(f'总用时:{e_time-s_time}秒')运行代码,在控制台中输入起始页码为1,结束页码为70,按下回车后输出的结果如下。总用时:23.332643747329712秒1.单线程爬虫耗时计算在4.6节的项目中,导入time模块,并在main语句中添加网络爬虫耗时计算的代码,修改后的代码如下。6.2.4多线程爬虫性能分析2.多线程爬虫耗时计算if__name__=='__main__':s_time=time.time()heima=HeiMa()heima.run()e_time=time.time()print(f'总用时:{e_time-s_time}秒')运行代码,在控制台中输入起始页码为1,结束页码为70,按下回车后输出的结果如下。所有任务完成!总用时:11.972748517990112秒在6.2.3节项目的main语句中添加网络爬虫耗时计算的代码,修改后的代码如下。6.2.4多线程爬虫性能分析通过比较单线程爬虫和多线程爬虫耗费的时长可知,在相同的条件下,多线程爬虫的性能优于单线程爬虫的性能。协程爬虫6.3熟悉协程爬虫的运行流程,能够归纳协程爬虫的运行流程学习目标6.3.1协程爬虫流程分析多线程爬虫通过开启多个线程并行抓取和解析网页,利用CPU切换线程执行的方式,在一定程度上提升了数据采集效率。然而,线程的创建和切换需要消耗系统资源,线程数量过多,反而会因频繁调度降低性能。而协程爬虫另辟蹊径,它基于单线程内的任务协作机制,通过非阻塞式的任务切换,在几乎不产生线程开销的前提下实现高效并发,为海量数据抓取提供了一种轻量级、高性能的解决方案。6.3.1协程爬虫流程分析6.3.1协程爬虫流程分析协程爬虫的运行流程如图所示。6.3.1协程爬虫流程分析01构建一个网址列表,用于保存所有待处理的网址,为后续协程调度任务做好准备。02为每个网址分配独立协程,单个线程内的协程会按顺序启动执行。每个协程遵循“抓取网页数据→解析网页数据”的逻辑,当某个协程遭遇网络请求阻塞或异常时,会立即切换至下一个协程执行,通过非阻塞式调度实现微观层面的任务并发。03将解析后处理的目标数据实时存入数据列表中。该列表作为临时存储载体,确保数据在采集与持久化之间的有序流转。04遍历数据列表,将提取的目标数据按指定格式完成最终存储。协程爬虫的运行流程如下。掌握协程爬虫的实现技术,能够使用asyncio和aiohttp库实现协程爬虫学习目标6.3.2协程爬虫实现技术Python的标准库asyncio为协程编程提供核心支持,常与第三方库aiohttp协作实现高效的协程爬虫,其中前者负责协程调度与事件循环,后者负责处理异步网络请求,而aiofiles库则可对解析后的数据进行异步写入,三者结合形成从网页抓取到数据存储的完整异步解决方案。6.3.2协程爬虫实现技术importasyncioasyncdefmain(): #定义协程
print('hello')awaitasyncio.sleep(1)#阻塞等待1秒
print('world')在asyncio库中,关键字async、await用于定义协程。其中,关键字async需要放在关键字def的前面,表明被修饰的函数是协程函数,而不是一个普通函数;关键字await位于协程函数内部,其后面需要跟可等待对象,比如协程对象、协程任务和Future类的对象,表示当前协程会在此处暂停执行并让出控制权。6.3.2协程爬虫实现技术1.asyncio库6.3.2协程爬虫实现技术asyncio.run(main()) 方式一1.asyncio库要想运行创建的协程,可以通过asyncio库的run()和run_until_complete()方法实现。importasyncioasyncdefcoroutine_one():#定义协程函数
print('hello')asyncdefcoroutine_two():#定义协程函数
print('world')asyncdefmain():#使用create_task()函数将协程封装成任务
task1=asyncio.create_task(coroutine_one())task2=asyncio.create_task(coroutine_two())awaittask1awaittask2loop=asyncio.new_event_loop()#创建新事件循环asyncio.set_event_loop(loop)#设置为当前循环loop.run_until_complete(main())#运行协程6.3.2协程爬虫实现技术方式二1.asyncio库要想运行创建的协程,可以通过asyncio库的run()和run_until_complete()方法实现。协程的异步执行虽然显著提升了程序的效率,但同时也带来了数据安全隐患。当多个协程同时访问共享资源(文件、数据库或内存中的数据结构)时,可能会引发数据竞争、内容覆盖等问题。为了保障数据的准确性,需要引入同步机制来协调协程间的操作。asyncio.Lock类作为专为异步环境设计的锁机制,它通过互斥访问的方式,确保同一时刻只有一个协程能够操作共享资源,从而避免数据竞争,让协程在高效运行的同时也能安全可靠地处理数据。6.3.2协程爬虫实现技术1.asyncio库asyncio.Lock类通过异步上下文管理器实现自动加锁与解锁。使用时需先通过该类的构造方法Lock()创建锁对象;当协程需要访问共享资源时,通过asyncwith语句获取锁,若锁处于未锁定状态,则立即执行被保护的代码块,并在执行完毕后自动释放锁;若锁已被其他协程持有,当前协程将自动挂起,在锁被释放后才继续执行。6.3.2协程爬虫实现技术1.asyncio库例如,通过3个协程向列表追加元素,使用asyncio.Lock类确保每次仅有一个协程执行追加操作,从而避免数据竞争导致的元素覆盖或顺序错乱问题,具体代码如下:6.3.2协程爬虫实现技术asyncdefmain():#创建任务列表,但不立即执行
task_list=[asyncio.create_task(worker(i))foriinrange(3)]fortaskintask_list:#逐个执行并等待任务完成
awaittaskprint(f"最终共享数据:{shared_data}")if__name__=="__main__":asyncio.run(main())importasyncioshared_data=[]#共享资源lock=asyncio.Lock()#创建锁对象asyncdefworker(task_id):print(f"任务{task_id}等待获取锁...")asyncwithlock:#自动获取和释放锁
print(f"任务{task_id}已获取锁,开始操作共享资源")shared_data.append(task_id)#修改共享数据
awaitasyncio.sleep(1)#模拟耗时操作
print(f"任务{task_id}释放锁")1.asyncio库运行代码,结果如下所示。6.3.2协程爬虫实现技术任务0等待获取锁...任务0已获取锁,开始操作共享资源任务1等待获取锁...任务2等待获取锁...任务0释放锁任务1已获取锁,开始操作共享资源任务1释放锁任务2已获取锁,开始操作共享资源任务2释放锁最终共享数据:[0,1,2]1.asyncio库aiohttp库是Python中基于asyncio实现的异步HTTP客户端/服务器的第三方库,在使用之前需要先进行安装。安装aiohttp库的具体命令如下。6.3.2协程爬虫实现技术pipinstallaiohttp==3.12.122.aiohttp库运行上述命令后,可以看到命令行窗口出现如下信息,表示aiohttp库安装成功。Successfullyinstalledaiohappyeyeballs-2.6.1aiohttp-3.12.12aiosignal-1.3.2frozenlist-1.7.0multidict-6.4.4propcache-0.3.2yarl-1.20.1aiohttp库中提供了一个status属性,status属性用于获取请求的状态码,另外aiohttp库中还提供了很多方法。6.3.2协程爬虫实现技术方法说明ClientSession()用于创建客户端会话text()以字符串形式显示服务器内容json()以JSON形式响应服务器内容read()返回原始二进制数据,适用于图片或文件下载post()发送POST请求get()发送GET请求2.aiohttp库使用aiohttp库的get()方法请求百度首页,具体代码如下所示。6.3.2协程爬虫实现技术importasyncio,aiohttpasyncdefmain():#使用with语句的上下文管理器,保证处理session之后正确关闭
asyncwithaiohttp.ClientSession()assession:#使用get()方法发送GET请求
asyncwithsession.get('/')asresp:print(resp.status)#输出响应状态码loop=asyncio.new_event_loop()#创建新事件循环asyncio.set_event_loop(loop)#设置为当前循环loop.run_until_complete(main())2.aiohttp库前面编写的爬虫程序解析完网页中的数据后,会将数据写入到本地文件中,但写入文件这一过程属于同步操作,并且会造成线程阻塞,也就是说程序在没有完成写入文件之前无法执行后续操作。对于此种情况,我们可以通过非阻塞的异步方式将数据写入文件中。aiofiles库提供了以非阻塞的异步方式操作文件写入,由于该库不是Python的标准库,在使用之前需要先进行安装。aiofiles库的安装命令如下。6.3.2协程爬虫实现技术pipinstallaiofiles==24.1.03.aiofiles库运行上述命令后,可以看到命令行窗口出现如下信息,表示aiofiles库安装成功Successfullyinstalledaiofiles-24.1.0aiofiles库中提供了许多与处理Python文件相似的方法,常用方法如下所示。6.3.2协程爬虫实现技术方法说明open()使用协程打开一个文件close()使用协程关闭文件read()使用协程读取文件,可设置读取的字节数readall()使用协程读取文件所有内容write()使用协程写入文件数据,可设置写入的字符长度writelines()使用协程写入文件数据,每次写入一行数据3.aiofiles库使用aiofiles库向文件写入并读取数据,具体如下。6.3.2协程爬虫实现技术importasyncio,aiofilesasyncdefwirte_demo():asyncwithaiofiles.open("text.txt","w",encoding="utf-8")asfp:awaitfp.write("helloworld")print("数据写入成功")asyncdefread_demo():asyncwithaiofiles.open("text.txt","r",encoding="utf-8")asfp:content=awaitfp.read()print(content)3.aiofiles库多学一招事件循环(Loop)是每个asyncio应用的核心。事件循环会运行异步任务和回调,执行网络I/O操作,以及运行子程序。简单来说,我们将协程任务(Task)注册到事件循环(Loop)上,事件循环会循环遍历协程任务的状态,当任务触发条件发生时就会执行对应的协程任务。await关键字后需要跟随可等待对象。“可等待”可理解为跳转到等待对象,并将当前任务挂起,当等待对象的任务处理完成,再跳回当前任务继续执行。asyncio库中的可等待对象包括协程对象、协程任务和Future对象。协程对象可理解为调用协程函数所返回的对象;协程任务是将协程包装成一个Task对象,用于注册到事件循环中;Future对象是一种特殊的低层级可等待对象,表示一个异步操作的最终结果。可等待对象和事件循环掌握协程爬虫的实现技术,能够使用协程技术抓取黑马程序员论坛网站数据学习目标6.3.3协程爬虫基本示例下面以黑马程序员论坛网站为例,带领大家一起使用aiohttp、asyncio和aiofiles模块实现协程爬虫,并让协程爬虫采集Python技术交流版块中所有帖子的文章标题、文章作者、文章链接以及发布时间。6.3.3协程爬虫基本示例6.3.3协程爬虫基本示例01导入程序需要使用的库或模块。02定义普通函数build_tasks(),用于构建网址列表。03定义协程函数main(),负责调度所有抓取任务。04定义请求并提取网页数据的fetch_parse_save()函数。05创建事件循环,启动协程函数。执行代码当程序运行后,可以看到在代码文件同级目录下添加了一个新的文件asyncio-heima.json,该文件存储了黑马程序员论坛中1~70页的文章标题、文章作者、文章链接和发布时间。6.3.3协程爬虫基本示例[单击查看源码]熟悉协程爬虫性能分析,能够计算出协程爬虫耗时时间学习目标6.3.4协程爬虫性能分析importtimeif__name__=='__main__':s_time=time.time()loop=asyncio.get_event_loop()#创建事件循环
loop.run_until_complete(main())e_time=time.time()print(f'总用时:{e_time-s_time}秒')为了对协程爬虫的性能进行分析,在6.3.3节示例代码的基础上,增加网络爬虫耗时计算的代码,比较单线程爬虫和协程爬虫在采集相同数据时总共耗费的时长。在6.3.3节示例中导入time模块,之后在main语句中添加网络爬虫耗时计算的代码,改后的代码如下。运行代码,结果如下。总用时:7.084892749786377秒6.3.4协程爬虫性能分析通过比较单线程爬虫和协程爬虫耗费的时长可知,在相同的条件下,协程爬虫的性能优于单线程爬虫的性能。6.3.4协程爬虫性能分析[单击查看源码]实践项目:采集黑马头条的评论列表6.4掌握黑马头条数据的抓取,能够使用多线程采集黑马头条的评论列表学习目标6.4实践项目:采集黑马头条的评论列表黑马头条是一个新闻资讯类项目,由用户端、自媒体端、管理后台端组成完整的业务闭环,通过大数据平台分析用户喜好,为用户精准推送资讯新闻。本节将运用多线程的知识开发一个多线程爬虫项目,采集黑马头条自媒体端指定页面范围的评论列表。项目需求6.4实践项目:采集黑马头条的评论列表访问黑马头条自媒体端登录页面,使用默认的账号密码登录后,在左侧的菜单栏中选择“内容管理”→“评论列表”进入评论列表页面。项目目标评论列表页面以表格形式罗列了标题、评论状态、总评论数、粉丝评论数、操作5列数据,默认展示第1页的数据。本项目要求采集评论列表页面中指定页码范围的标题、评论状态、总评论数和粉丝评论数。6.4实践项目:采集黑马头条的评论列表本项目基于多线程爬虫的运行流程,将实现过程分为3步,分别为构建网址队列、抓取和解析网页数据、存储数据。下面对这3步的操作进行具体分析。项目分析6.4实践项目:采集黑马头条的评论列表1.构建网址队列在评论列表页面
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2026年药品质检实验室洁净区与非洁净区压差控制
- 空气污染与慢性病管理的个体化防护方案
- 2026年厂内机动车安全事故应急处置预案
- 2026年如何设计幼儿园教学论文
- 书香翰府读书分享会暨文化沙龙活动方案
- 高中2025励志故事悟道理说课稿
- 科研激励政策对创新产出的影响分析
- 科研团队梯队建设的科研诚信教育
- 神经认知障碍的精准认知康复个体化家庭训练指导
- 护理技能操作规范与技巧
- 2026年中质协CAQ六西格玛黑带-控制-习题道模拟考试试卷(历年真题)附答案详解
- 2026我国虚拟现实技术应用行业市场调研及发展趋势与投资前景预测报告
- 2026年安徽省合肥市经开区中考语文二模试卷(含详细答案解析)
- 2026上半年广东省铁路建设投资集团有限公司管理人员社会招聘备考题库含答案详解(能力提升)
- 2025-2026学年江苏省南京市栖霞区七年级(下)期中英语试卷含答案
- 算电协同关键技术 (课件)
- 2026年医疗事业单位编制公共基础知识考点预测真题题库(含答案)
- 2026年甘肃兰州市初二学业水平地理生物会考考试试题及答案
- 2026年党章党纪党规应知应会知识测试题库(含答案)
- 2026年及未来5年市场数据中国实体书店行业市场发展现状及投资前景展望报告
- 社区采购询价制度
评论
0/150
提交评论