Python网络爬虫基础教程(第2版)课件 第6-11章 提升网络爬虫速度 -分布式网络爬虫Scrapy-Redis_第1页
Python网络爬虫基础教程(第2版)课件 第6-11章 提升网络爬虫速度 -分布式网络爬虫Scrapy-Redis_第2页
Python网络爬虫基础教程(第2版)课件 第6-11章 提升网络爬虫速度 -分布式网络爬虫Scrapy-Redis_第3页
Python网络爬虫基础教程(第2版)课件 第6-11章 提升网络爬虫速度 -分布式网络爬虫Scrapy-Redis_第4页
Python网络爬虫基础教程(第2版)课件 第6-11章 提升网络爬虫速度 -分布式网络爬虫Scrapy-Redis_第5页
已阅读5页,还剩501页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第6章提升网络爬虫速度《Python网络爬虫基础教程(第2版)》学习目标/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.构建网址队列在评论列表页面中右击,在弹出的快捷菜单中选择“查看网页源代码”,搜索不到任何关于评论的数据,由此可推断评论数据是动态加载的,此时可以进一步尝试查找评论数据请求的接口。通过浏览器开发者工具的网络面板筛选异步请求,定位到一条关键的AJAX请求。预览该请求的响应数据,如图所示。项目分析6.4实践项目:采集黑马头条的评论列表1.构建网址队列从预览响应数据中可以看出,响应数据是JSON格式的,只包含评论列表第1页的信息,说明该请求为评论数据的接口。查看接口使用的URL及其参数,如图所示。项目分析6.4实践项目:采集黑马头条的评论列表1.构建网址队列在评论列表页面的请求URL及其参数中,URL查询字符串中的参数page表示当前的页码,per_page表示每页显示的数据条数,response_type表示响应的类型。为了便于查找请求URL的规律,这里对前5页的请求URL进行罗列,具体结果如下。项目分析第1页:/mp/v1_0/articles?page=1&per_page=10&response_type=comment第2页:/mp/v1_0/articles?page=2&per_page=10&response_type=comment第3页:/mp/v1_0/articles?page=3&per_page=10&response_type=comment第4页:/mp/v1_0/articles?page=4&per_page=10&response_type=comment第5页:/mp/v1_0/articles?page=5&per_page=10&response_type=comment6.4实践项目:采集黑马头条的评论列表2.抓取和解析网页数据由于只有在登录后才能访问评论列表页面,因此在发送请求时需携带身份凭证。分析登录后发送的请求头,发现请求头中包含Authorization字段,如图所示。项目分析6.4实践项目:采集黑马头条的评论列表项目分析Authorization字段含有服务器用于验证用户代理身份的凭证。我们向发送请求时,需要在请求头中携带这个字段便能获取授权数据。由于接口响应数据是JSON格式的,所以这里可以将其转换为字典。通过分析响应数据的结构,确定目标字段的位置之后,根据字典的键获取目标数据,并将数据放入队列中。6.4实践项目:采集黑马头条的评论列表项目分析3.存储数据这里直接将解析后的目标数据写入JSON文件中。6.4实践项目:采集黑马头条的评论列表(1)导入程序中所需使用的库或模块。(2)定义表示多线程爬虫的HeiMaTouTiao类,在该类的构造方法中添加表示请求头、网址队列和网页数据队列的属性。(3)定义用于构造网址列表的populate_url()方法。该方法会将根据页码拼接好的URL添加到网址队列中。(4)定义用于发送请求并提取数据的get_data()方法。该方法会获取网址队列中的URL并发送GET请求。服务器返回响应后将从JSON数据中提取目标数据,并将目标数据添加到网页数据队列中。(5)定义用于保存网页数据的save_data()方法。该方法会从网页数据队列中取出数据,并将数据写入指定的JSON文件中。(6)定义用于控制网络爬虫运行流程的run()方法。该方法会根据用户输入的起始页码和结束页码,开启多个线程抓取和解析网页数据、1个线程构建请求URL、1个线程保存数据。(7)在main语句中创建HeiMaTouTiao类的对象,让该对象调用run()方法运行网络爬虫。下面按照前面的思路编写多线程爬虫程序,采集黑马头条自媒体端评论列表的相关数据,具体内容如下。项目实现6.4实践项目:采集黑马头条的评论列表本章小结在本章中,首先介绍了网络爬虫速度提升方案,然后介绍了多线程爬虫,最后介绍了协程爬虫。通过本章内容的学习,读者能够熟练地在网络爬虫程序中使用多线程和协程技术,提升网络爬虫程序采集数据的效率。本章小结第7章存储数据《Python网络爬虫基础教程(第2版)》学习目标/Target了解数据存储的两种方式,能够说出文件存储和数据库存储的利弊掌握MongoDB数据库的安装方式,能够独立安装MongoDB数据库掌握Python操作MongoDB数据库的方式,能够使用pymongo库操作MongoDB数据库掌握Redis数据库的安装,能够独立在计算机上安装Redis数据库掌握Python操作Redis的方式,能够使用redis库操作Redis数据库章节概述/Summary在实际应用中,网络爬虫在完成网页数据的抓取与解析后,会提取出最终需要的目标数据,这些数据需通过持久化存储加以留存,为后续的数据研究工作提供基础支撑。数据存储主要分为文件存储和数据库存储两种方式,其中文件存储我们在前面的项目开发中已有所接触,在本章中,着重介绍使用数据库存储网络爬虫采集到的数据。目录/Contents7.17.27.3数据存储的方式存储至MongoDB数据库存储至Redis数据库7.4实践项目:采集小兔鲜儿网的商品信息数据存储方式7.1了解数据存储的两种方式,能够说出文件存储和数据库存储的利弊学习目标7.1数据存储的方式数据存储是网络爬虫开发的关键收尾环节,主要任务是将解析后的结构化数据进行持久化存储,为后续的数据分析建模、趋势预测研究等工作提供数据支持。从实际应用来看,网络爬虫采集的数据主要通过两种方式实现存储。7.1数据存储的方式文件存储是网络爬虫数据存储中最基础、最易上手的方式。它通过将解析后的数据直接以文件形式保存到本地计算机的磁盘中,完成数据的持久化。前文中涉及的多个爬虫案例,均采用这种方式实现数据存储。这种方式的优势在于无需依赖额外的软件或服务,操作流程简单直观,对于数据量较小、结构单一的中小型爬虫场景,能以极低的技术成本满足需求,是入门级开发者的理想选择。7.1数据存储的方式1.文件存储尽管文件存储能实现数据的基本留存,但在处理大规模、多维度数据时存在明显局限:大量文件会零散分布在本地目录中,不仅占用冗余存储空间,更会导致数据结构混乱,难以通过程序高效调用。此时,数据库存储便成为更优解,它借助专业的数据库管理系统,对数据进行规范化的结构化存储,支持按字段分类管理,并能通过索引机制快速定位目标数据,有效避免重复存储问题。无论是百万级数据的批量写入,还是复杂条件的精准查询,数据库都能提供高效稳定的支持,更适合数据量庞大、业务逻辑复杂的大型网络爬虫场景。7.1数据存储的方式2.数据库存储根据存储数据时所用数据模型的不同,当今互联网中的数据库主要分为关系数据库、非关系数据库两种,分别介绍如下。关系数据库关系数据库采用严谨的二维表格关系模型来组织数据,其核心特征在于数据的高度结构化和规范化。这类数据库由相互关联的数据表构成,每个表包含行(记录实体)和列(字段属性),表间通过主外键约束建立关联关系。在使用前必须明确定义表结构,包括字段名称、数据类型、约束条件等元数据信息。这种严格的结构化设计虽然降低了灵活性,但确保了数据的完整性和一致性,支持复杂的多表关联查询和事务处理。7.1数据存储的方式2.数据库存储根据存储数据时所用数据模型的不同,当今互联网中的数据库主要分为关系数据库、非关系数据库两种,分别介绍如下。非关系数据库非关系数据库也被称为NoSQL(NotOnlySQL)数据库,它突破了传统关系模型的限制,采用更加灵活的数据组织方式。其显著特点是支持动态模式,允许不同记录拥有不同的字段结构,能够原生存储JSON文档、键值对等非结构化数据。这种设计牺牲了部分一致性,但获得了更高的水平扩展性、写入性能和灵活性,特别适合处理用户画像、日志数据、社交网络关系等。7.1数据存储的方式2.数据库存储非关系数据库非关系数据库根据数据模型的不同,主要可分为以下3种类型:列存储数据库、键值存储数据库和文档型数据库,每种类型都具有独特的存储结构和适用场景。其中,键值存储数据库采用简单的键值对结构,通过唯一的键快速访问对应的值,具有极高的读写性能,Redis是其典型代表,常被用作缓存系统。文档型数据库则在键值存储的基础上进行了扩展,采用类似JSON或XML的文档格式存储数据,每个文档可以包含多个嵌套的键值对,支持更复杂的数据结构查询,MongoDB就是这类数据库的杰出代表。7.1数据存储的方式2.数据库存储7.1数据存储的方式在数据存储方案的选择上,开发者需要根据项目规模、性能需求和业务场景进行综合考量。对于小规模测试或临时性数据,文件存储以其部署简单、无需额外服务的优势成为理想选择;而对于海量数据、高并发访问或长期存储的生产环境,数据库存储凭借其强大的索引优化、事务支持和分布式架构展现出显著优势。本书将重点讲解MongoDB和Redis这两种在网络爬虫开发中比较常用的非关系型数据库,详细介绍如何在Python中使用它们进行数据存储、查询和管理操作,帮助读者掌握实际项目中最实用的数据库操作技能。存储至MongoDB数据库7.2掌握MongoDB数据库的安装,能够独立安装MongoDB数据库学习目标7.2存储至MongoDB数据库

7.2.1下载与安装MongoDBMongoDB作为当前最流行的文档型数据库之一,采用了灵活高效的文档存储数据,每个文档都是一个包含多个键值对的独立单元。与关系型数据库不同,它对数据结构的约束极为宽松,具有结构可动态调整、查询响应迅速的显著特点。在使用MongoDB数据库之前,需要确保自己的计算机中已经安装了MongoDB数据库。本节以Windows10操作系统为例,介绍如何在计算机中下载并安装MongoDB数据库。7.2.1下载与安装MongoDB在浏览器中访问MongoDB社区版的下载页面,该页面中默认展示Windows系统支持的版本,具体如图所示。1.下载MongoDB截止本书完稿时,MongoDB的最新版本是8.0.10。单击“Download”按钮,开始将相应的安装包mongodb-windows-x86_64-8.0.10-signed下载到本地。多线程7.2.1下载与安装MongoDB步骤1步骤2步骤3步骤4MongoDB欢迎界面双击刚刚下载的安装包mongodb-windows-x86_64-8.0.10-signed.msi启动安装程序,进入WelcometotheMongoDB8.0.10界面,如图所示。2.安装MongoDB7.2.1下载与安装MongoDB步骤2步骤1步骤3步骤4勾选协议单击欢迎界面中的“Next”按钮,进入End-UserLicenseAgreement界面,如图所示。2.安装MongoDB7.2.1下载与安装MongoDB步骤3步骤1步骤2步骤4进入ChooseSetupType界面选中“IacceptthetermsintheLicenseAgreement”复选框,单击“Next”按钮进入ChooseSetupType界面,如图所示。Complete:此类型将会自动安装所有程序功能,需占用较多的磁盘空间,建议大多数用户使用。Custom:此类型允许用户自行选择要安装的程序功能及安装位置,建议有自定义需求的用户使用。2.安装MongoDB7.2.1下载与安装MongoDB步骤4步骤1步骤2步骤3进入ServiceConfiguration界面单击“Complete”按钮,进入ServiceConfiguration界面,如图所示。data文件夹:会存放创建的数据库文件。log文件夹:会存放数据库的日志文件。多线程7.2.1下载与安装MongoDB步骤5步骤6步骤7步骤8进入InstallMongoDBCompass界面保持默认选项,单击“Next”按钮,进入InstallMongoDBCompass界面,如图所示。7.2.1下载与安装MongoDB步骤6步骤5步骤7步骤8进入ReadytoinstallMongoDB界面取消勾选“InstallMongoDBCompass”复选框,单击“Next”按钮进入ReadytoinstallMongoDB8.0.102008R2PlusSSL(64bit)界面,如图所示。7.2.1下载与安装MongoDB步骤7步骤5步骤6步骤8进入CompletedtheMongoDB8.0.10界面单击“Install”按钮开始安装MongoDB数据库,并以进度条的形式持续显示当前安装的进度,安装完成后自动进入CompletedtheMongoDB8.0.10界面,如图所示。7.2.1下载与安装MongoDB步骤8步骤5步骤6步骤7完成安装单击“Finish”按钮完成安装。值得一提的是,MongoDB默认会将创建的数据库文件存储在data文件夹下的目录db,但是这个文件夹不会被自动创建,用户需要在MongoDB安装完成后手动创建目录db。在“C:\ProgramFiles\MongoDB\Server\8.0\data\”目录下创建一个文件夹db,此时的data目录结构如图所示。7.2.1下载与安装MongoDB步骤8步骤5步骤6步骤7完成安装打开命令提示符窗口,使用cd命令切换当前工作路径为MongoDB.exe所在的安装目录(本书安装的路径为“C:\ProgramFiles\MongoDB\Server\4.2\bin”),之后输入如下命令指定MongoDB数据库文件的位置为刚刚新建的db目录。mongod--dbpath"C:\ProgramFiles\MongoDB\Server\4.2\data\db"为了避免后续重复切换至MongoDB.exe的安装目录,可以将以上路径添加到环境变量中。打开命令提示符窗口,使用命令切换路径至MongoDB所在的安装目录(本书安装的路径为“C:\ProgramFiles\MongoDB\Server\8.0\bin”),之后输入如下命令手动启动MongoDB数据库服务,并指定数据库文件的存储路径为刚刚新建的db目录。mongod--dbpath"C:\ProgramFiles\MongoDB\Server\8.0\data\db"为了避免后续启动MongoDB服务器时,重复切换至MongoDB的安装目录,此处可以将以上安装目录添加到环境变量中。7.2.1下载与安装MongoDB掌握Python操作MongoDB的方式,能够使用pymongo库操作MongoDB数据库学习目标7.2.2使用Python操作MongoDB安装MongoDB数据库后,开发者可以通过Python的第三方库pymongo轻松操作MongoDB。该库提供了Python与MongoDB之间的高效数据交互支持,涵盖数据库连接管理、集合操作、灵活的CRUD(增删改查)、聚合查询、索引优化以及事务处理等核心功能,帮助开发者高效完成数据存储与检索任务。7.2.2使用Python操作MongoDB使用pymongo库之前,需要在当前的Python环境中安装pymongo库。安装指定版本pymongo库的命令如下。pipinstallpymongo==4.13.2当命令提示符窗口中输出如下信息时,说明pymongo库安装成功。7.2.2使用Python操作MongoDB……Installingcollectedpackages:dnspython,pymongoSuccessfullyinstalleddnspython-2.7.0pymongo-4.13.2安装好pymongo库以后,就可以使用pymongo库操作MongoDB数据库了。接下来,分别从创建连接、访问数据库、创建集合、插入文档、查询文档、更新文档、删除文档这几个方面介绍pymongo库的基本操作。7.2.2使用Python操作MongoDB在对MongoDB数据库的数据进行操作之前,需要先与本地的MongoDB数据库建立连接。在pymongo库中,MongoClient类的对象用于建立与MongoDB数据库的连接,它可以通过如下构造方法进行创建。__init__(self,host=None,port=None,document_class=dict,tz_aware=None,connect=None,type_registry=None,**kwargs)host:用于指定数据库所在的主机地址,默认值为'localhost',即本地主机。port:用于指定连接的端口号,默认值为27017,即数据库默认使用的端口号。document_class:用于指定数据库执行查询操作后返回文档的类型,默认值为dict,即查询结果将以字典形式返回。7.2.2使用Python操作MongoDB1.创建连接使用默认的主机地址和端口号建立与本地MongoDB数据库的连接。代码如下所示。client=MongoClient()显式地指定主机地址和端口号,示例代码如下。client=MongoClient('localhost',27017)使用MongoDB的URL路径形式传入参数,示例代码如下。client=MongoClient('mongodb://localhost:27017')7.2.2使用Python操作MongoDB1.创建连接在pymongo模块中,DataBase对象表示一个数据库。访问数据库的方式比较简单,可以直接使用“连接对象.数据库名称”的方式访问数据库。db=client.database_test#访问数据库database_test此外,还可以使用字典的形式进行访问,示例代码如下。db=client['database_test']值得一提的是,使用以上两种方式访问数据库时,若指定的数据库已经存在,则会直接访问该数据库,否则会重新创建一个数据库。7.2.2使用Python操作MongoDB2.访问数据库在pymongo模块中,Collection对象代表MongoDB中的集合,其概念类似于关系数据库中的表,但是没有固定的结构。创建集合与访问数据库的方式类似,直接通过“数据库名称.集合名称”的方式实现。coll=db.student#创建集合student也可以采用访问字典值的形式创建集合,示例代码如下。coll=db['student']7.2.2使用Python操作MongoDB3.创建集合7.2.2使用Python操作MongoDB4.插入文档集合创建完成后,即可向其中插入文档。文档是MongoDB数据库的基本数据单元,类似于关系型数据库中的记录行。在pymongo库中,文档以字典形式表示,每个文档都包含一个特殊的_id字段,用于唯一标识该文档。若插入时未显式指定_id,MongoDB将自动生成一个唯一的ObjectId值。pymongo库提供了两个向集合中插入文档的方法,分别是insert_one()和insert_many()。result=coll.insert_one({'name':'zhaoliu','age':23})insert_many()用于一次向集合中插入多条文档,代码如下。result=coll.insert_many([{'name':'zhangsan','age':20},{'name':'lisi','age':21},{'name':'wangwu','age':22}])insert_one()用于一次向集合中插入一条文档,代码如下。7.2.2使用Python操作MongoDB4.插入文档7.2.2使用Python操作MongoDB4.插入文档运行插入文档的代码,程序第一次输出一个InsertOneResult对象,说明成功插入了一个文档;程序第二次输出一个InsertManyResult对象,说明成功插入了多个文档。7.2.2使用Python操作MongoDB5.查询文档pymongo库提供了两个查询文档的方法,分别是find_one()方法和find()方法。其中,find_one()方法用于查询集合中符合条件的一个文档,若找到匹配的文档,则返回第一个匹配到的文档,否则返回None;find()方法用于查询集合中符合条件的多个文档,若找到匹配项,则返回一个可迭代的Cursor对象。result=coll.find({'age':20})print(result)可以使用for循环遍历查找的结果。fordocinresult:print(doc)使用find()方法查询集合student中age值为20的所有文档,代码如下。7.2.2使用Python操作MongoDB5.查询文档7.2.2使用Python操作MongoDB6.更新文档pymongo库提供了两个更新文档的方法,分别是update_one()和update_many()。其中,update_one()方法用于更新集合中第一个匹配筛选条件的一个文档;update_many()方法用于更新集合中所有匹配筛选条件的多个文档。这两个方法接收两个必选参数filter和update,其中参数filter用于指定筛选条件,参数update用于指定更新操作,支持使用$set、$inc等更新操作符实现字段修改、数值增减等操作。使用update_one()方法更新name为zhaoliu的文档,将该文档的age值设为25,并查看修改后的结果,示例代码如下。coll.update_one({'name':'zhaoliu'},{'$set':{'age':25}})result_update=col

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论