当前位置: 首页 > news >正文

python【多线程、单线程、异步编程】三个版本--在爬虫中的应用

并发编程在爬虫中的应用

之前的课程,我们已经为大家介绍了 Python 中的多线程、多进程和异步编程,通过这三种手段,我们可以实现并发或并行编程,这一方面可以加速代码的执行,另一方面也可以带来更好的用户体验。爬虫程序是典型的 I/O 密集型任务,对于 I/O 密集型任务来说,多线程和异步 I/O 都是很好的选择,因为当程序的某个部分因 I/O 操作阻塞时,程序的其他部分仍然可以运转,这样我们不用在等待和阻塞中浪费大量的时间。

下面我们以爬取“360图片”网站的图片并保存到本地为例,为大家分别展示使用单线程、多线程和异步 I/O 编程的爬虫程序有什么区别,同时也对它们的执行效率进行简单的对比。

“360图片”网站的页面使用了 Ajax 技术,这是很多网站都会使用的一种异步加载数据和局部刷新页面的技术。简单的说,页面上的图片都是通过 JavaScript 代码异步获取 JSON 数据并动态渲染生成的,而且整个页面还使用了瀑布式加载(一边向下滚动,一边加载更多的图片)。我们在浏览器的“开发者工具”中可以找到提供动态内容的数据接口,如下图所示,我们需要的图片信息就在服务器返回的 JSON 数据中。

在这里插入图片描述

例如,要获取“美女”频道的图片,我们可以请求如下所示的URL,其中参数ch表示请求的频道,=后面的参数值beauty就代表了“美女”频道,参数sn相当于是页码,0表示第一页(共30张图片),30表示第二页,60表示第三页,以此类推。

https://image.so.com/zjl?ch=beauty&sn=0

单线程版本

通过上面的 URL 下载“美女”频道共90张图片。

"""
example04.py - 单线程版本爬虫
"""
import osimport requestsdef download_picture(url):filename = url[url.rfind('/') + 1:]resp = requests.get(url)if resp.status_code == 200:with open(f'images/beauty/{filename}', 'wb') as file:file.write(resp.content)def main():if not os.path.exists('images/beauty'):os.makedirs('images/beauty')for page in range(3):resp = requests.get(f'https://image.so.com/zjl?ch=beauty&sn={page * 30}')if resp.status_code == 200:pic_dict_list = resp.json()['list']for pic_dict in pic_dict_list:download_picture(pic_dict['qhimg_url'])if __name__ == '__main__':main()

在 macOS 或 Linux 系统上,我们可以使用time命令来了解上面代码的执行时间以及 CPU 的利用率,如下所示。

time python3 example04.py 

下面是单线程爬虫代码在我的电脑上执行的结果。

python3 example04.py  2.36s user 0.39s system 12% cpu 21.578 total

这里我们只需要关注代码的总耗时为21.578秒,CPU 利用率为12%

多线程版本

我们使用之前讲到过的线程池技术,将上面的代码修改为多线程版本。

"""
example05.py - 多线程版本爬虫
"""
import os
from concurrent.futures import ThreadPoolExecutorimport requestsdef download_picture(url):filename = url[url.rfind('/') + 1:]resp = requests.get(url)if resp.status_code == 200:with open(f'images/beauty/{filename}', 'wb') as file:file.write(resp.content)def main():if not os.path.exists('images/beauty'):os.makedirs('images/beauty')with ThreadPoolExecutor(max_workers=16) as pool:for page in range(3):resp = requests.get(f'https://image.so.com/zjl?ch=beauty&sn={page * 30}')if resp.status_code == 200:pic_dict_list = resp.json()['list']for pic_dict in pic_dict_list:pool.submit(download_picture, pic_dict['qhimg_url'])if __name__ == '__main__':main()

执行如下所示的命令。

time python3 example05.py

代码的执行结果如下所示:

python3 example05.py  2.65s user 0.40s system 95% cpu 3.193 total

异步I/O版本

我们使用aiohttp将上面的代码修改为异步 I/O 的版本。为了以异步 I/O 的方式实现网络资源的获取和写文件操作,我们首先得安装三方库aiohttpaiofile,命令如下所示。

pip install aiohttp aiofile

aiohttp 的用法在之前的课程中已经做过简要介绍,aiofile模块中的async_open函数跟 Python 内置函数open的用法大致相同,只不过它支持异步操作。下面是异步 I/O 版本的爬虫代码。

"""
example06.py - 异步I/O版本爬虫
"""
import asyncio
import json
import osimport aiofile
import aiohttpasync def download_picture(session, url):filename = url[url.rfind('/') + 1:]async with session.get(url, ssl=False) as resp:if resp.status == 200:data = await resp.read()async with aiofile.async_open(f'images/beauty/{filename}', 'wb') as file:await file.write(data)async def fetch_json():async with aiohttp.ClientSession() as session:for page in range(3):async with session.get(url=f'https://image.so.com/zjl?ch=beauty&sn={page * 30}',ssl=False) as resp:if resp.status == 200:json_str = await resp.text()result = json.loads(json_str)for pic_dict in result['list']:await download_picture(session, pic_dict['qhimg_url'])def main():if not os.path.exists('images/beauty'):os.makedirs('images/beauty')loop = asyncio.get_event_loop()loop.run_until_complete(fetch_json())loop.close()if __name__ == '__main__':main()

执行如下所示的命令。

time python3 example06.py

代码的执行结果如下所示:

python3 example06.py  0.82s user 0.21s system 27% cpu 3.782 total

总结

通过上面三段代码执行结果的比较,我们可以得出一个结论,使用多线程和异步 I/O 都可以改善爬虫程序的性能,因为我们不用将时间浪费在因 I/O 操作造成的等待和阻塞上,而time命令的执行结果也告诉我们,单线程的代码 CPU 利用率仅仅只有12%,而多线程版本的 CPU 利用率则高达95%;单线程版本的爬虫执行时间约21秒,而多线程和异步 I/O 的版本仅执行了3秒钟。另外,在运行时间差别不大的情况下,多线程的代码比异步 I/O 的代码耗费了更多的 CPU 资源,这是因为多线程的调度和切换也需要花费 CPU 时间。至此,三种方式在 I/O 密集型任务上的优劣已经一目了然,当然这只是在我的电脑上跑出来的结果。如果网络状况不是很理想或者目标网站响应很慢,那么使用多线程和异步 I/O 的优势将更为明显,有兴趣的读者可以自行试验。

相关文章:

python【多线程、单线程、异步编程】三个版本--在爬虫中的应用

并发编程在爬虫中的应用 之前的课程,我们已经为大家介绍了 Python 中的多线程、多进程和异步编程,通过这三种手段,我们可以实现并发或并行编程,这一方面可以加速代码的执行,另一方面也可以带来更好的用户体验。爬虫程…...

大模型LLM相关面试题整理-位置编码-tokenizer-激活函数-layernorm

10 LLMs 位置编码篇 10.1.1 什么是位置编码? 位置编码是一种用于在序列数据中为每个位置添加位置信息的技术。在自然语言处理中,位置编码通常用于处理文本序列。由于传统的神经网络无法直接捕捉输入序列中的位置信息,位置编码的引入可以帮助…...

python在nacos注册微服务

安装 首先需要安装python的nacos sdk pip install nacos-sdk-python 注册 注册过程非常简单,需要注意的是,注册完要定时发送心跳,否则服务会被nacos删掉。 import nacos import timeSERVER_ADDRESSES "http://1.2.3.4:8848" …...

tuxera ntfs2024破解版mac电脑磁盘读写软件

大家都知道由于操作系统的原因,在苹果电脑上不能够读写NTFS磁盘,但是,今天小编带来的这款tuxera ntfs 2024 mac版,完美的解决了这个问题。这是一款在macOS平台上使用的磁盘读写软件,能够实现苹果Mac OS X系统读写Micro…...

【源码】C++坦克大战源码

文章目录 题目介绍你收到的所有文件源码效果展示报告内容 题目介绍 代码量:1450 语言:C 你收到的所有文件 其中一个是devc版本,也可以用visual stdio 运行。 源码效果展示 typedef struct //这里的出现次序指的是一个AI_ta…...

AIO开放接口平台免费畅享ChatGPT聊天、联网互动、学术等服务!更有DALL·E 3最强AI绘图功能!

免费畅享! AIO平台ChatGPT联网、聊天、学术等服务! AIO开放接口平台 | 服务介绍 ALL IN ONE (AIO)API服务是LLM(大语言模型)开放接口平台:持续接入各种主流的大模型接口,并提供简单、易用、统一的API交互…...

【python】屈小原现在要为学校写校庆贺文(CTGU百年校庆)

题目: """ 题目描述: 屈小原需要为学校的校庆写一篇贺文,共需写下n个字,但他目前只完成了1个字。屈小原可以进行两种操作: 在文档的末尾添加一个字,这样字数就会变为x1。 写下与当前字数相同…...

探索未来的视觉革命:卷积神经网络的崭新时代(二)

💗💗💗欢迎来到我的博客,你将找到有关如何使用技术解决问题的文章,也会找到某个技术的学习路线。无论你是何种职业,我都希望我的博客对你有所帮助。最后不要忘记订阅我的博客以获取最新文章,也欢…...

博客后台模块续更(三)

四、后台模块-动态路由 实现了这个动态路由功能之后,就能在浏览器web页面登录进博客管理后台了 1. 接口分析 后台系统需要能实现不同的用户权限可以看到不同的功能,即左侧的导航栏 请求方式 请求地址 请求头 GET /getRouters 需要token请求头 …...

第十二届蓝桥杯模拟赛第三期

A填空题 问题描述 请问在 1 到 2020 中&#xff0c;有多少个数与 2020 互质&#xff0c;即有多少个数与 2020 的最大公约数为 1。 参考答案 800 public class Main {public static void main(String[] args) {int ans0;for(int i1;i<2020;i) {if(gcd(2020,i)1) {ans;}}…...

2023年浙大MEM考前80天上岸经验分享

时间过得真快&#xff0c;转眼间已经是十月份了。回想起去年这个时候&#xff0c;我还在为考研而感到焦虑不安。然而&#xff0c;如今我已经在浙大MEM项目学习了一个多月的时间了。在这一个月的学习过程中&#xff0c;我不仅学到了许多专业知识&#xff0c;还结识了很多志同道合…...

增加并行度后,发现Flink窗口不会计算的问题。

文章目录 前言一、现象二、结论三、解决 前言 窗口没有关闭计算的问题&#xff0c;一直困扰了很久&#xff0c;经过多次验证&#xff0c;确定了问题的根源。 一、现象 Flink使用了window&#xff0c;同时使用了watermark &#xff0c;并且还设置了较高的并行度。生产是设置了…...

使用 JMeter 和 Docker 进行服务存根

用于性能测试的服务存根&#xff1a;简介 随着测试项目的复杂性不断增加&#xff0c;越来越多的被测系统的测试流程受到依赖系统的影响。当我说“依赖系统”时&#xff0c;我指的是&#xff1a; 不受当前开发影响的遗留系统 属于另一个组织的第三方服务 您的组织开发的系统&am…...

《王道计算机考研——操作系统》学习笔记总目录+思维导图

本篇文章是对《王道计算机考研——操作系统》所有知识点的笔记总结归档和计算机网络的思维导图 学习视频&#xff1a;王道计算机考研 操作系统 408四件套【计网、计组、操作系统、数据结构】完整课堂PPT 思维导图 &#xff08;求Star~&#xff09;&#xff1a;【王道考研】计…...

多模态及图像安全的探索与思考

前言 第六届中国模式识别与计算机视觉大会&#xff08;The 6th Chinese Conference on Pattern Recognition and Computer Vision, PRCV 2023&#xff09;已于近期在厦门成功举办。通过参加本次会议&#xff0c;使我有机会接触到许多来自国内外的模式识别和计算机视觉领域的研究…...

基础算法相关笔记

排序 最好情况下&#xff1a; 冒泡排序 最坏时间复杂度 O ( n 2 ) O(n^2) O(n2)。 插入排序 最坏时间复杂度为 O ( n 2 ) O(n^2) O(n2)&#xff0c;最优时间复杂度为 O ( n ) O(n) O(n)。 平均情况下&#xff1a; 快速排序 最坏时间复杂度为 O ( n 2 ) O(n^2) O(n2)&…...

Mac电脑无法识别移动硬盘怎么办?

很多人都喜欢在Mac电脑上办公、学习&#xff0c;但有时我们将移动硬盘连接Mac电脑时&#xff0c;却会发现电脑无法识别移动硬盘。那么&#xff0c;Mac电脑无法识别移动硬盘怎么办呢&#xff1f; Mac无法识别移动硬盘的原因 导致Mac不识别移动硬盘的原因有很多&#xff0c;你可…...

14Maven与Tomcat面试题

1MAVEN Maven是一个基于项目对象模型&#xff08;POM&#xff09;的项目管理工具&#xff0c;它可以帮助开发者自动化构建、依赖管理、项目报告等。Maven通过一个中央信息片段能够管理项目的构建、报告和文档等步骤&#xff0c;同时也能够管理项目的依赖。Maven的核心概念是POM…...

会议OA小程序【首页布局】

目录 一. Flex布局介绍 1.1 什么是Flex布局 1.2 基本概念 1.3 Flex属性 二. 会议OA首页轮播图的实现 配置 Mock工具 swiper 效果展示 三. 会议OA首页会议信息布局 index.js index.wxml index.wxss 首页整体效果展示 一. Flex布局介绍 布局的传统解决方案&#x…...

高效表达三步

一、高效表达 高效表达定主题搭架子填素材 第一&#xff1a; 1个核心主题&#xff0c;让别人秒懂你的想法 &#xff08;表达要定主题&#xff09; 第二&#xff1a; 3种经典框架&#xff0c;帮你快速整理表达思路 第三&#xff1a; 2种表达素材&#xff0c;让发言更具说服力…...

基于距离变化能量开销动态调整的WSN低功耗拓扑控制开销算法matlab仿真

目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.算法仿真参数 5.算法理论概述 6.参考文献 7.完整程序 1.程序功能描述 通过动态调整节点通信的能量开销&#xff0c;平衡网络负载&#xff0c;延长WSN生命周期。具体通过建立基于距离的能量消耗模型&am…...

Swift 协议扩展精进之路:解决 CoreData 托管实体子类的类型不匹配问题(下)

概述 在 Swift 开发语言中&#xff0c;各位秃头小码农们可以充分利用语法本身所带来的便利去劈荆斩棘。我们还可以恣意利用泛型、协议关联类型和协议扩展来进一步简化和优化我们复杂的代码需求。 不过&#xff0c;在涉及到多个子类派生于基类进行多态模拟的场景下&#xff0c;…...

Linux相关概念和易错知识点(42)(TCP的连接管理、可靠性、面临复杂网络的处理)

目录 1.TCP的连接管理机制&#xff08;1&#xff09;三次握手①握手过程②对握手过程的理解 &#xff08;2&#xff09;四次挥手&#xff08;3&#xff09;握手和挥手的触发&#xff08;4&#xff09;状态切换①挥手过程中状态的切换②握手过程中状态的切换 2.TCP的可靠性&…...

Springcloud:Eureka 高可用集群搭建实战(服务注册与发现的底层原理与避坑指南)

引言&#xff1a;为什么 Eureka 依然是存量系统的核心&#xff1f; 尽管 Nacos 等新注册中心崛起&#xff0c;但金融、电力等保守行业仍有大量系统运行在 Eureka 上。理解其高可用设计与自我保护机制&#xff0c;是保障分布式系统稳定的必修课。本文将手把手带你搭建生产级 Eur…...

九天毕昇深度学习平台 | 如何安装库?

pip install 库名 -i https://pypi.tuna.tsinghua.edu.cn/simple --user 举个例子&#xff1a; 报错 ModuleNotFoundError: No module named torch 那么我需要安装 torch pip install torch -i https://pypi.tuna.tsinghua.edu.cn/simple --user pip install 库名&#x…...

R语言速释制剂QBD解决方案之三

本文是《Quality by Design for ANDAs: An Example for Immediate-Release Dosage Forms》第一个处方的R语言解决方案。 第一个处方研究评估原料药粒径分布、MCC/Lactose比例、崩解剂用量对制剂CQAs的影响。 第二处方研究用于理解颗粒外加硬脂酸镁和滑石粉对片剂质量和可生产…...

使用LangGraph和LangSmith构建多智能体人工智能系统

现在&#xff0c;通过组合几个较小的子智能体来创建一个强大的人工智能智能体正成为一种趋势。但这也带来了一些挑战&#xff0c;比如减少幻觉、管理对话流程、在测试期间留意智能体的工作方式、允许人工介入以及评估其性能。你需要进行大量的反复试验。 在这篇博客〔原作者&a…...

STM32HAL库USART源代码解析及应用

STM32HAL库USART源代码解析 前言STM32CubeIDE配置串口USART和UART的选择使用模式参数设置GPIO配置DMA配置中断配置硬件流控制使能生成代码解析和使用方法串口初始化__UART_HandleTypeDef结构体浅析HAL库代码实际使用方法使用轮询方式发送使用轮询方式接收使用中断方式发送使用中…...

Vite中定义@软链接

在webpack中可以直接通过符号表示src路径&#xff0c;但是vite中默认不可以。 如何实现&#xff1a; vite中提供了resolve.alias&#xff1a;通过别名在指向一个具体的路径 在vite.config.js中 import { join } from pathexport default defineConfig({plugins: [vue()],//…...

大模型——基于Docker+DeepSeek+Dify :搭建企业级本地私有化知识库超详细教程

基于Docker+DeepSeek+Dify :搭建企业级本地私有化知识库超详细教程 下载安装Docker Docker官网:https://www.docker.com/ 自定义Docker安装路径 Docker默认安装在C盘,大小大概2.9G,做这行最忌讳的就是安装软件全装C盘,所以我调整了下安装路径。 新建安装目录:E:\MyS…...