Python爬虫之协程

Python爬虫之协程

为什么要用协程
协程声明
await
aiohttp
aiofiles
案例修改
案例完整代码

为什么要用协程

  1. 轻量级:协程是轻量级的执行单元,可以在同一个线程中并发执行。相比于多线程或多进程,创建和切换协程的开销更小。
  2. 高效利用资源:由于协程可以在同一个线程中并发执行,因此不会涉及多个线程或进程之间的上下文切换,从而减少了额外的开销。这使得协程能够高效地利用计算资源。
  3. 简化并发编程:协程采用显式的挂起和恢复机制,程序员可以明确控制协程的执行流程。相比于多线程或多进程的共享内存模型,协程通过显式的消息传递(如使用 awaitasyncio.Queue 等)来实现数据交换,简化了并发编程的复杂性。
  4. 异步非阻塞:协程通常与异步编程一起使用,可以在 I/O 密集型任务中实现非阻塞的操作。通过使用 await 关键字等待 I/O 操作完成时,可以在等待期间释放 CPU,执行其他协程任务,提高整体的并发性能。

协程声明

创建协程函数:async def func()

运行协程函数:asyncio.run(func())

注意:当调用协程函数func()后,内部代码是不会执行的,只是得到了一个协程对象,如果想要运行协程对象,则必须将其交给事件循环来处理

import asyncioasync def func():print("Hello, coroutine!")# 调用协程
asyncio.run(func())

也可以这么写

import asyncioasync def func():print("Hello, coroutine!")# 创建事件循环对象
loop = asyncio.get_event_loop()# 将事件封装为任务
task = loop.create_task(func())# 运行事件直到任务完成
loop.run_until_complete(task)

执行时间循环:.wait().gather

  • await asyncio.wait(tasks):接受一个任务集合作为参数,并等待所有任务完成。返回两个集合(Sets):已完成的任务集合和仍在进行中的任务集合。

  • await asyncio.gather(*tasks):接受一个任务集合作为参数,并等待所有任务完成。返回每个任务的实际返回值

  • await task:执行单个任务,返回每个任务的实际返回值

await

await关键字后面可以定义可等待对象,例如协程对象,Future,Task对象

此处的可等待对象其实就是I/O阻塞,当await包裹的协程任务遇到阻塞时会自动从当前任务切换到另一个任务中,以节省时间和内存

result = await 表示result就是await后面的指令运行完毕后得到的结果

import asyncioasync def fun1():print('1')await asyncio.sleep(2)return '结束'async def main():# 创建任务task1 = asyncio.create_task(fun1())task2 = asyncio.create_task(fun1())# 创建事件循环res1 = await task1res2 = await task2print(res1, res2)asyncio.run(main())

也可以这么写

import asyncioasync def fun1():print('1')await asyncio.sleep(2)return '结束'async def main():# 创建任务task = [asyncio.create_task(fun1()) for i in range(10)]# 创建事件循环res = await asyncio.gather(task)print(res)asyncio.run(main())

数量太少看不出效率,但是可以证明await会等待所有任务返回结果后再继续往下运行

image-20240122213003553

aiohttp

aiohttprequests相比最大的区别就是aiohttp支持异步操作,因此用协程编写爬虫时aiohttp是相当重要的一个模块

aiohttp.ClientSession()

  • 用于创建异步的HTTP客户端会话对象
  • 通过该对象发送异步请求并处理响应

session.get(url)session.post(url)

  • ClientSeesion对象上调用这些方法可以发送GET/POST请求
  • url作为参数传递,一般就是访问的主网址

response.statusresponse.text()

  • 这俩响应ClientResponse对象的属性和方法
  • response.status返回响应状态码(如200、404等)
  • response.status返回响应内容的文本字符串

response.json()

  • 当服务器返回JSON格式的响应是,可以用该方法将响应内容解析为Python对象(字典、列表)

async with session.get(url) as responseasync with session.post(url) as response

  • 使用async with语法结构,可以在异步上下文管理器中发送请求和处理响应
  • response是一个异步上下文管理器返回的响应对象,可以执行response.status之类的操作,并且使其能够被await包裹

利用aiohttp模块获取一个简单的浏览器响应

import asyncio
import aiohttp
from lxml import etreeurl = 'https://www.baidu.com'async def main():connector = aiohttp.TCPConnector(ssl=False)async with aiohttp.ClientSession(connector=connector) as session:async with session.get(url) as response:res = await response.text()et = etree.HTML(res)print(et)if __name__ == '__main__':asyncio.run(main())

aiofiles

aiofiles与python中常用的with open操作类似,并且支持异步操作,且与asyncio配合良好

具体操作也和with open类似

async def read_file():async with aiofiles.open('file.txt', mode='r') as file:contents = await file.read()print(contents)if __name__ == '__main__':asyncio.run(read_file())

async def write_file():async with aiofiles.open('file.txt', mode='w') as file:await file.write('Hello, World!')if __name__ == '__main__':asyncio.run(write_file())

案例修改

掏出上次我们写的线程池爬虫案例:

from concurrent.futures import ThreadPoolExecutorimport requests
from lxml import etreeurl = 'https://loryx.wiki/%E6%B5%8F%E8%A7%88/%E7%89%8C%E5%BA%93'def download(name, src):with open(name, 'wb') as f:f.write(requests.get(src).content)print(f'{name}已下载')def main():res = requests.get(url=url)res.encoding = 'utf-8'et = etree.HTML(res.text)src = et.xpath("//td[@class='col15 leftalign']/a/@href")name = et.xpath("//td[@class='col0 leftalign']/text()")for i, index in enumerate(name):name[i] = index.strip()with ThreadPoolExecutor(64) as t:for i in range(len(src)):file_name = f"img/{name[i]}.png"t.submit(download, file_name, src[i])if __name__ == '__main__':main()

现在开始改写

首先跟requests相关的可以全部删了换成aiohttp,比如

res = requests.get(url=url)res.encoding = 'utf-8'et = etree.HTML(res.text)

替换为

async with aiohttp.ClientSession(connector=connector) as session:async with session.get(url) as response:res = await response.text()
et = etree.HTML(res)

然后ThreadPoolExecutor相关的也可以全部用asyncio替换

for i, index in enumerate(name):name[i] = index.strip()with ThreadPoolExecutor(64) as t:for i in range(len(src)):file_name = f"img/{name[i]}.png"t.submit(download, file_name, src[i])

替换为

tasks = []
for i in range(len(src)):file_name = f"img/{name[i]}.png"if not os.path.exists('img'):os.makedirs('img')task = asyncio.create_task(spider(file_name, src[i]))tasks.append(task)
await asyncio.gather(*tasks)

文件读写的部分也可以用aiofiles重写

def download(name, src):with open(name, 'wb') as f:f.write(requests.get(src).content)print(f'{name}已下载')

替换成

async def spider(name, src):connector = aiohttp.TCPConnector(ssl=False)async with aiohttp.ClientSession(connector=connector) as session:async with session.get(src) as response:count = await response.read()async with aiofiles.open(name, 'wb') as f:await f.write(count)print(f'{name}已下载')

案例完整代码

import asyncio
import os.pathimport aiofiles
import aiohttp
from lxml import etreeurl = 'https://loryx.wiki/%E6%B5%8F%E8%A7%88/%E7%89%8C%E5%BA%93'async def spider(name, src):# 关闭SSL证书验证connector = aiohttp.TCPConnector(ssl=False)# 创建图片链接对象async with aiohttp.ClientSession(connector=connector) as session:async with session.get(src) as response:# 读取图片信息 准备写入本地count = await response.read()# 写入本地 下载时遇到io阻塞自动跳转其他任务async with aiofiles.open(name, 'wb') as f:await f.write(count)print(f'{name}已下载')async def main():# 关闭SSL证书验证connector = aiohttp.TCPConnector(ssl=False)# 创建异步HTTP客户端对象async with aiohttp.ClientSession(connector=connector) as session:# 发送get请求async with session.get(url) as response:# 返回响应内容的字符串res = await response.text()et = etree.HTML(res)src = et.xpath("//td[@class='col15 leftalign']/a/@href")  # 图片链接temp_name = et.xpath("//td[@class='col0 leftalign']/text()")  # 图片名称for i, index in enumerate(temp_name):temp_name[i] = index.strip()# 任务列表tasks = []for i in range(len(src)):# 下载到本地的名称file_name = f"img/{temp_name[i]}.png"if not os.path.exists('img'):os.makedirs('img')# 批量创建asyncio异步任务 执行spider函数task = asyncio.create_task(spider(file_name, src[i]))tasks.append(task)# 启动await asyncio.wait(tasks)if __name__ == '__main__':asyncio.run(main())(src)):# 下载到本地的名称file_name = f"img/{temp_name[i]}.png"if not os.path.exists('img'):os.makedirs('img')# 批量创建asyncio异步任务 执行spider函数task = asyncio.create_task(spider(file_name, src[i]))tasks.append(task)# 启动await asyncio.wait(tasks)if __name__ == '__main__':asyncio.run(main())

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/244553.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Git 入门精讲

我们为什么要学习git? 就当下的发展而言,只要你从事开发就一定会接触git。作为最强大的分布式版本控制器,git 与 svn 有着本质上的区别。 Git是一种分布式版本控制系统,每个开发者都可以在本地维护完整的代码库,可以离…

Nas-FPN(CVPR 2019)原理与代码解析

paper:NAS-FPN: Learning Scalable Feature Pyramid Architecture for Object Detection third-party implementation:https://github.com/open-mmlab/mmdetection/tree/main/configs/nas_fpn 本文的创新点 本文采用神经网络结构搜索(Neur…

ctfshow-反序列化(web267-web270)

目录 web267 web268 web269 web270 总结 web267 页面用的什么框架不知道 看源码看一下 框架就是一种软件工具,它提供了一些基础功能和规范,可以帮助开发者更快地构建应用程序。比如Yii框架和ThinkPHP框架就是两个流行的PHP框架,它们提供…

SpringBoot集成mybatis时idea控制台中文乱码问题解决

在application.yml中配置好映射文件打印数据库日志文件时,控制台出现乱码的情况解决如下 问题 在执行查询操作的时候,查询时可以查看是没有问题的,但是控制台乱码了 解决 在File-Setting-Editor-File Encodings中设置如图所示就可以了 现在…

激光无人机打击系统——光束控制和指向系统

激光无人机(UAV)打击系统中的光束控制和指向系统通常包括以下几个关键组件和技术: 激光发射器:这是系统的核心,负责生成高能量的激光束。常用的激光类型包括固体激光器、化学激光器、光纤激光器等,选择取决…

Hive-SQL语法大全

Hive SQL 语法大全 基于语法描述说明 CREATE DATABASE [IF NOT EXISTS] db_name [LOCATION] path; SELECT expr, ... FROM tbl ORDER BY col_name [ASC | DESC] (A | B | C)如上语法,在语法描述中出现: [],表示可选,如上[LOCATI…

学单片机前先学什么?

学单片机前先学什么? 在开始前我有一些资料,是我根据网友给的问题精心整理了一份「单片机的资料从专业入门到高级教程」, 点个关注在评论区回复“888”之后私信回复“888”,全部无偿共享给大家!!&#xff…

[计算机网络]基本概念

目录 1.ip地址和端口号 1.1IP地址 1.2端口号 2.认识协议 2.1概念: 2.2知名协议的默认端口 3.五元组 4.协议分层 4.1分层的作用 4.2OSI七层模型 4.3TCP/IP五层(四层)模型 ​编辑4.4网络设备对应的分层: ​编辑以下为跨…

使用PHP自定义一个加密算法,实现编码配合加密,将自己姓名的明文加密一下

<meta charset"UTF-8"> <?phpfunction customEncrypt($lin, $key mySecretKey){// 定义一个简单的替换规则$li array(L > M, I > Y, Y > O, A > N, E > Q, );$yan ;for($i 0; $i < strlen($lin); $i){$char $lin[$i];if(isset($li[…

这才是问界M9惊艳到你的10大配置

文 | AUTO芯球 作者 | 李诞 盘点M9的十项科技&#xff0c;看看有没有惊艳到你&#xff1f; 一、猫头转向&#xff0c;5米2的大型SUV转弯可5.8米&#xff0c; 比很多我们的额家用小车的转弯半径都小&#xff0c;好开。 二、大灯抠图&#xff0c;夜晚开启大灯可以不晃对面车的…

Python列表与元组

Python 列表和元组是Python编程语言中两种重要的数据结构&#xff0c;它们在实际的编程中扮演着不可或缺的角色。本文将深入探讨Python列表和元组的特性、用法以及它们之间的区别&#xff0c;帮助读者更好地理解和运用这两种数据结构。 Python 列表 Python 列表是一种有序、可…

SpringBoot+Vue充电桩管理系统 附带详细运行指导视频

文章目录 一、项目演示二、项目介绍三、运行截图四、主要代码1. 分页获取预约数据代码2.保存预约信息代码3.修改订单状态代码 一、项目演示 项目演示地址&#xff1a; 视频地址 二、项目介绍 项目描述&#xff1a;这是一个基于SpringBootVue框架开发的充电桩管理系统。首先&…

postgresql(Windows)初始化数据库教程

省流&#xff1a;本文章内容讲的是如何初始化postgresql数据库环境&#xff0c;前提是已经安装好postgresql数据库&#xff0c;安装步骤参考postgresql&#xff08;Windows&#xff09;安装教程 # 开始&#xff1a;安装postgresql-12.14-2-windows-x64.exe完成后进行初始化数据…

指针-回调函数

回调函数的含义 回调函数通常作为参数传递给其他函数&#xff0c;它是一个通过函数指针调用的函数。简单来说这个函数的作用就是用来在特殊的条件满足时用来调用其他函数的一个函数。 回调函数的使用 当相同或者相似的函数出现多份的时候&#xff0c;那么由于相同的部分出现…

【后端技术】术有千法,道本归一

目录 1.概述 2.机器的问题 2.1.计算 2.2.存储 2.3.传输 3.人的问题 3.1.代码工程的管理 3.2.过程的把控 4.总结 1.概述 术有千法&#xff0c;道本归一。 之所以这样说&#xff0c;是因为当前出现的纷繁复杂的后端技术&#xff0c;其本质其实都是为了解决同一套问题。…

Node.JS CreateWriteStream(大容量写入文件流优化)

Why I Need Node.JS Stream 如果你的程序收到以下错误&#xff0c;或者需要大容量写入很多内容(几十几百MB甚至GB级别)&#xff0c;则必须使用Stream文件流甚至更高级的技术。 Error: EMFILE, too many open files 业务场景&#xff0c;我们有一个IntradayMissingRecord的补…

Webpack5 基本使用 - 3(完结)

环境区分 可以定义多个配置文件&#xff0c;通过 webpack-merge 合并配置文件。 安装 webpack-merge yarn add webpack-merge公共配置 // webpack.common.js const path require(path) const HtmlWebpackPlugin require(html-webpack-plugin)module.exports {entry: path…

Spring第七天(AOP)

简介 AOP(Aspect Oriented Programing)面向切面编程&#xff0c;一种编程范式&#xff0c;指导开发者如何组织程序结构 作用 在不惊动原始设计的基础上为其进行功能增强 Spring理念&#xff1a;无入侵式/无侵入式 基本概念 连接点(JoinPoint) : 程序执行过程中的任意位置&a…

5分钟做自己的微信红包封面

文章目录 怎么制作自己的红包封面&#xff1f;开通红包封面的要求如下&#xff1a;收费情况制作具体网站&#xff1a;https://chatapi.onechat.fun/register?affYoU6 提交审核logo封面、挂件、气泡证明材料 发放红包封面其他 怎么制作自己的红包封面&#xff1f; 开通红包封面…

离了个大谱,只因外貌被换角?

♥ 为方便您进行讨论和分享&#xff0c;同时也为能带给您不一样的参与感。请您在阅读本文之前&#xff0c;点击一下“关注”&#xff0c;非常感谢您的支持&#xff01; 文 |猴哥聊娱乐 编 辑|徐 婷 校 对|侯欢庭 电视剧选角也能如此抓马&#xff0c;真是让人大开眼界。还没开…