aiohttp 的使用

基本介绍

aiohttp 是一个基于 asyncio 的异步 HTTP 网络模块, 它即提供了服务端, 又提供了客户端。其中,我们用服务端可以搭建一个支持异步处理的服务器,这个服务器就是用来处理请求并返回响应的,类似于 Django , Flask , Tornado 等一些 Web 服务器。 而客户端可以用来发送请求,类似于使用 requests 发起一个HTTP 请求然后获得响应, 但 requests 发起的是同步网络请求, aiohttp 则是异步的

官方文档:Welcome to AIOHTTP — aiohttp 3.9.5 documentation

基本实例

import aiohttp
import asyncio
import nest_asyncio
nest_asyncio.apply()

async def fetch(session, url):
    async with session.get(url) as response:
        return await response.text(), response.status

async def main():
    async with aiohttp.ClientSession() as session:
        html, status = await fetch(session, 'https://cuiqingcai.com')
        print(f'html: {html[:100]}...')
        print(f'status:{status}')

if __name__ == '__main__':
    loop = asyncio.get_event_loop()
    loop.run_until_complete(main())

html: <!DOCTYPE html>
<html lang="zh-CN"><head><meta charset="UTF-8"><meta name="viewport" content...
status:200

这里可以看到我们成功的获取了网页源代码和响应尊和响应状态码200,也就是完成了一次基本HTTP请求,当然,这样的请求 requests 也可以做到

aiohttp 的请求定义:

在导入库的时候,除了必须导入 aiohttp 这个库,还要导入 asyncio 库,因为要实现异步爬取,需要启动协程,而协程需要借助 asyncio 库中的事件循环才能执行。 除了事件循环之外, asyncio 里面也提供了很多基础的异步操作

每个异步方法的前面都要统一加上 async 来修饰。

with as 前面同样需要加上 async 来修饰。 在 python 中, with as 用于声明一个上下文管理器,能够帮我们自动分配和释放资源。而在异步方法中 ,with as  前面加上 async 代表声明一个支持异步的上下文管理器

对于一些返回协程对象的操作,前面需要加上 await 来修饰。 例如 response 调用的 text 方法,查询 API 可以发现, 其返回的是协程对象,那么前面就要加 await 。 对于状态码来说,其返回的就是一个数值,因此前面不需要加 await 。 所以这里可以按照实际情况来处理,参考官方文档说明,看看其对应的返回值是怎样的类型,然后决定加不加 await 就可以了

最后,定义完爬取方法之后,实际上是 main 方法调用了 fetch 方法,要运行的话,必须启用事件循环,而事件循环需要使用 asyncio 库, 然后调用 run_until_complete 方法来运行

注意: 在Python 3.7 之后的版本中,我们可以使用 asyncio.run(mai()) 代替最后的启动操作,不需要显示声明事件循环, run 方法内部会自动启动一个事件循环。

import aiohttp
import asyncio
import nest_asyncio
nest_asyncio.apply()

async def fetch(session, url):
    async with session.get(url) as response:
        return await response.text(), response.status

async def main():
    async with aiohttp.ClientSession() as session:
        html, status = await fetch(session, 'https://cuiqingcai.com')
        print(f'html: {html[:100]}...')
        print(f'status:{status}')

asyncio.run(main())

html: <!DOCTYPE html>
<html lang="zh-CN"><head><meta charset="UTF-8"><meta name="viewport" content...
status:200

效果一样

url 参数设置

对于URL 参数设置,我们可以使用 params 参数,传入一个字典即可

import aiohttp
import asyncio

async def main():
    params = {'name': 'germey', 'age': 25}
    async with aiohttp.ClientSession() as session:
        async with session.get('http://www.httpbin.org/get', params=params) as response:
            print(await response.text())
if __name__=='__main__':
    asyncio.run(main())

{"args": {"age": "25", "name": "germey"}, "headers": {"Accept": "*/*", "Accept-Encoding": "gzip, deflate, br", "Host": "www.httpbin.org", "User-Agent": "Python/3.11 aiohttp/3.9.3", "X-Amzn-Trace-Id": "Root=1-66a21748-480d5a6e579d1a3b3cd1a710"}, "origin": "117.152.24.110", "url": "http://www.httpbin.org/get?name=germey&age=25"
}

这里可以看到,实际请求的URL 为 http://www.httpbin.org/get?name=germey&age=25 ,其中参数对应的是 params 中的内容

其他请求类型

aiohttp 还支持其他请求类型, 例如 POST ,PUT ,DELETE 等

session.post('http://www.httpbin.org/post',fdata=b'data')

session.put('http://www.httpbin.org/put',fdata=b'data')

session.delete('http://www.httpbin.org/post',fdata=b'data')

POST 请求

对于 POST 表单提交,其对应的请求头中的 Content-Type 为 application/x-www-form-urlencoded

import aiohttp
import asyncio

async def main():
    data = {'name': 'germey', 'age': 25}
    async with aiohttp.ClientSession() as session:
        async with session.post('https://www.httpbin.org/post', data=data) as response:
            print(await response.text())
if __name__== '__main__':
    asyncio.run(main())

{"args": {}, "data": "", "files": {}, "form": {"age": "25", "name": "germey"}, "headers": {"Accept": "*/*", "Accept-Encoding": "gzip, deflate, br", "Content-Length": "18", "Content-Type": "application/x-www-form-urlencoded", "Host": "www.httpbin.org", "User-Agent": "Python/3.11 aiohttp/3.9.3", "X-Amzn-Trace-Id": "Root=1-66a21972-0acc966c70ce51551219c086"}, "json": null, "origin": "117.152.24.110", "url": "https://www.httpbin.org/post"
}

对于POST JSON 数据的提交, 其对应的请求头中的 Content-Type 为 application/json, 我们只需要将 post 方法里的 data 参数改成 json 即可

import aiohttp
import asyncio

async def main():
    data = {'name': 'germey', 'age': 25}
    async with aiohttp.ClientSession() as session:
        async with session.post('https://www.httpbin.org/post', json=data) as response:
            print(await response.text())
if __name__== '__main__':
    asyncio.run(main())

{"args": {}, "data": "{\"name\": \"germey\", \"age\": 25}", "files": {}, "form": {}, "headers": {"Accept": "*/*", "Accept-Encoding": "gzip, deflate, br", "Content-Length": "29", "Content-Type": "application/json", "Host": "www.httpbin.org", "User-Agent": "Python/3.11 aiohttp/3.9.3", "X-Amzn-Trace-Id": "Root=1-66a21abd-5bd0bcc5362a212746b15be4"}, "json": {"age": 25, "name": "germey"}, "origin": "117.152.24.110", "url": "https://www.httpbin.org/post"
}

响应

对于响应来说,我们可以用如下方法获取其中的状态码, 响应体, 响应体二进制内容,响应体JSON结果

import aiohttp
import asyncio

async def main():
    data = {'name': 'germey', 'age': 25}
    async with aiohttp.ClientSession() as session:
        async with session.post('https://www.httpbin.org/post', data=data) as response:
            print('status:', response.status)
            print('headers:', response.headers)
            print('body:', await response.text())
            print('bytes:', await response.read())
            print('json:', await response.json())
if __name__ == '__main__':
    asyncio.run(main())

status: 200
headers: <CIMultiDictProxy('Date': 'Thu, 25 Jul 2024 09:35:42 GMT', 'Content-Type': 'application/json', 'Content-Length': '516', 'Connection': 'keep-alive', 'Server': 'gunicorn/19.9.0', 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Credentials': 'true')>
body: {"args": {}, "data": "", "files": {}, "form": {"age": "25", "name": "germey"}, "headers": {"Accept": "*/*", "Accept-Encoding": "gzip, deflate, br", "Content-Length": "18", "Content-Type": "application/x-www-form-urlencoded", "Host": "www.httpbin.org", "User-Agent": "Python/3.11 aiohttp/3.9.3", "X-Amzn-Trace-Id": "Root=1-66a21c6d-0bd06f745165ce7917c83621"}, "json": null, "origin": "117.152.24.110", "url": "https://www.httpbin.org/post"
}bytes: b'{\n  "args": {}, \n  "data": "", \n  "files": {}, \n  "form": {\n    "age": "25", \n    "name": "germey"\n  }, \n  "headers": {\n    "Accept": "*/*", \n    "Accept-Encoding": "gzip, deflate, br", \n    "Content-Length": "18", \n    "Content-Type": "application/x-www-form-urlencoded", \n    "Host": "www.httpbin.org", \n    "User-Agent": "Python/3.11 aiohttp/3.9.3", \n    "X-Amzn-Trace-Id": "Root=1-66a21c6d-0bd06f745165ce7917c83621"\n  }, \n  "json": null, \n  "origin": "117.152.24.110", \n  "url": "https://www.httpbin.org/post"\n}\n'
json: {'args': {}, 'data': '', 'files': {}, 'form': {'age': '25', 'name': 'germey'}, 'headers': {'Accept': '*/*', 'Accept-Encoding': 'gzip, deflate, br', 'Content-Length': '18', 'Content-Type': 'application/x-www-form-urlencoded', 'Host': 'www.httpbin.org', 'User-Agent': 'Python/3.11 aiohttp/3.9.3', 'X-Amzn-Trace-Id': 'Root=1-66a21c6d-0bd06f745165ce7917c83621'}, 'json': None, 'origin': '117.152.24.110', 'url': 'https://www.httpbin.org/post'}

可以看到这里有些字段需要加上 await 有些不需要,其原则是, 如果返回的是一个协程对象(如 async 修饰的方法),那么前面就要加上 await 具体可以看 aiohttp 的 API 其链接为: https://docs.aiohttp.org/en/stable/client_reference.html

超时设置

我们可以借助 ClientTimeout 对象设置超时, 例如 1秒时间可以这样设置

import aiohttp
import asyncio

async def main():
    timeout = aiohttp.ClientTimeout(total=1)
    async with aiohttp.ClientSession(timeout=timeout) as session:
        async with session.get('https://www.httpbin.org/get') as response:
            print('status:', response.status)
if __name__ == '__main__':
    asyncio.get_event_loop().run_until_complete(main())

如果在 1 秒内成功获取响应结果如下

status: 200

如果失败

并发限制

由于 aiohttp 可以支持非常高的并发量,如几万,十万, 百万都是能做到的,但是面对如此高的并发量,目标网站可能无法再短时间内响应,而且有瞬间将目标网站爬挂掉的风险,这提示我们要控制一下爬取的并发量

一般情况下,可以借助 asyncio 的 Semaphore 来控制并发量

import asyncio
import aiohttp

CONCURRENCY = 5
URL = 'https://www.baidu.com'

semaphore = asyncio.Semaphore(CONCURRENCY)
session = None

async def scrape_api():
    async with semaphore:
        print('scraping', URL)
        async with session.get(URL) as response:
            await asyncio.sleep(1)
            return await response.text()

async def main():
    global session
    session = aiohttp.ClientSession()
    scrape_index_tasks = [asyncio.ensure_future(scrape_api()) for _ in range(10000)]
    await asyncio.gather(*scrape_index_tasks)

if __name__=='__main__':
    asyncio.run(main())

这里我们声明了 CONCURRENCY (代表爬取最大并发量) 为 5, 同时声明爬取的目标 URL 为百度。 接着,借助 Semaphore 创建了一个信号量对象,将其赋值为 semaphore , 这样就可以用它来控制最大并发量了。 这里我们把 semaphore 直接放在了对应的爬取方法里, 使用 async with 语句将 semaphore 作为上下文管理对象即可。 这样一来,信号便可以控制进入爬取的最大协程数量,即我们声明的 CONCURRENCY 的值

在main 方法里, 我们声明了 10000 个 task ,将其传递给 gather 方法运行, 倘若不加以限制,那么 这 10000 个 task 会被同时执行, 并发量相当的大,但是有了信号量的控制之后,同时运行的 task 数量会被控制在 5个, 这样就能给 aiohttp 限制速度了

 

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

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

相关文章

Ansible的脚本-----playbook剧本【下】

目录 实战演练六&#xff1a;tags 模块 实战演练七&#xff1a;Templates 模块 实战演练六&#xff1a;tags 模块 可以在一个playbook中为某个或某些任务定义“标签”&#xff0c;在执行此playbook时通过ansible-playbook命令使用--tags选项能实现仅运行指定的tasks。 playboo…

一个注解解决重复提交问题

一、前言 ​ 在应用系统中提交是一个极为常见的功能&#xff0c;倘若不加管控&#xff0c;极易由于用户的误操作或网络延迟致使同一请求被发送多次&#xff0c;从而生成重复的数据记录。针对用户的误操作&#xff0c;前端通常会实现按钮的 loading 状态&#xff0c;以阻…

行业不同怎么选企业管理咨询公司

在选择企业管理咨询公司时&#xff0c;不同行业的企业往往面临着各自独特的挑战和需求。因此&#xff0c;选择一家适合自身行业特点、能够提供专业且有针对性的咨询服务的管理咨询公司至关重要。本文将从行业差异的角度出发&#xff0c;探讨如何根据企业所在行业的不同&#xf…

SQL-REGEX-常见正则表达式的使用

SQL-REGEX-常见正则表达式的使用 在SQL中&#xff0c;正则表达式&#xff08;Regex&#xff09;的使用可以帮助进行更灵活和精确的模式匹配和数据筛选。不同的数据库管理系统对于正则表达式的支持略有差异&#xff0c;但大体都是相似的。 Tips&#xff1a; 模式描述匹配内容…

【python】PyQt5中QCommandLinkButton的详细教程与应用实战

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…

【Linux】socket 套接字 / 序列化与反序列化

目录 一. TCP 网络程序简易计算器1. 核心功能2. 程序结构3. 服务器初始化4. 服务器启动5. 业务处理6. 客户端初始化7. 客户端启动 二. 序列化与反序列化1. 协议2. 序列化与反序列化 一. TCP 网络程序 简易计算器 1. 核心功能 客户端向服务器发送数据, 服务器进行计算并返回结…

墨烯的C语言技术栈-C语言基础-018

char c; //1byte字节 8bit比特位 int main() { int a 10; //向内存申请四个字节,存储10 &a; //取地址操作符 return 0; } 每个字节都有地址 而a的地址就是它第一个字节的地址 要先开始调试才可以查看监控和查看内存 左边是地址 中间是内存中的数据 最后面的是…

Jenkins - apt 安装软件包 404 Not Found

Jenkins - apt 安装软件包 404 Not Found 引言关于 apt解决 apt 安装软件包 404 问题问题分析解决方案 引言 日常 Jenkins job 运行&#xff0c;有段时间会遇到 apt 安装软件包 404 的情况&#xff0c;这种情况不是每次都发生的&#xff0c;但是会导致 Jenkins 失败&#xff0…

【HTML — 构建网络】HTML 入门

在本文中,我们将介绍 HTML 的绝对基础知识。为了帮助您入门,本文定义了元素、属性以及您可能听说过的所有其他重要术语。它还解释了这些在 HTML 中的位置。您将学习 HTML 元素的结构、典型的 HTML 页面的结构以及其他重要的基本语言功能。在此过程中,也将有机会玩转 HTML! …

上传项目到GitHub

上传项目到GitHub 前期工作&#xff1a;创建GitHub仓库 1.使用git命令初始化文件夹 git init2.将文件夹里面所有的文件添加到本地仓库&#xff0c;如果想添加单个文件&#xff0c;将.换成文件名就好。 git add .3.给文件备注&#xff0c;双引号里面是文件备注的内容 git c…

大揭秘:百度云提供支持的智能审核机制是什么?

在论坛、社媒等公共空间里&#xff0c;用户不仅能自主上传信息&#xff0c;还可以通过评论、群聊等方式进行互动。 如果不对信息进行审核&#xff0c;平台可能会涌现大量包含暴力、仇恨、淫秽或其他不当内容的帖子。用人工方式一条条审核信息&#xff0c;不仅成本高、效率低、…

C 观察者模式 Demo

目录 一、基础描述 二、Demo 最近需要接触到 MySQL 半同步插件&#xff0c;发现其中用到了观察者模式&#xff0c;之前没在 C 中用过&#xff0c;遂好奇心驱使下找了找资料&#xff0c;并写了个 Demo。 一、基础描述 观察者设计模式&#xff08;Observer Pattern&#xff0…

vue2文章添加多个标签思路代码及效果展示

效果展示 思路 data数据结构 第一个数组&#xff0c;用来存放标签库&#xff0c;供创建文章时选择 第二个数组&#xff0c;用来存放从标签库选中后的标签&#xff0c; 且选中后需在可选的标签库里删除&#xff0c;否则出现同一个标签被多次添加 js代码 点击输入框&#xf…

智能APK动态防护系统:自动重命名与签名,实现安全分发

本智能APK动态防护系统通过集成先进的自动化处理技术&#xff0c;实现了对APK文件的深度定制化与安全性强化。系统核心功能包括自动反编译APK、随机生成包名与签名、代码混淆等&#xff0c;最终回编译生成独一无二的APK安装包。这一过程每5分钟&#xff08;时间间隔可自定义&am…

Windows下ORACLE数据泵expdp和impdp使用

Windows下ORACLE数据泵expdp和impdp使用 一、基础环境 操作系统&#xff1a;Windows server 2008&#xff1b; 数据库版本&#xff1a;Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production 数据库工具&#xff1a;PL/SQL 12.0.7 实验内容&…

示例:WPF中如何处理TabControl页面绑定ItemsSource切换TabItem时UI数据没有持久保存的问题

一、目的&#xff1a;在WPF开发过程中&#xff0c;经常用到TabControl&#xff0c;也会遇到类似问题&#xff0c;用TabControl绑定数据源ItemsSource时&#xff0c;切换TabItem时&#xff0c;UI上的数据没有持久保存&#xff0c;本文介绍一种处理方式&#xff0c;可以做到缓存页…

什么是云服务器ecs,为什么要选择云服务器

云服务器 ECS&#xff08;Elastic Compute Service&#xff09;是阿里云&#xff08;Alibaba Cloud&#xff09;提供的一种基于云计算的虚拟服务器服务。它允许用户在云端虚拟化环境中配置和管理服务器&#xff0c;无需投资物理硬件、提高资源利用率、降低维护成本、实现快速部…

Sed工具

文章目录 一、sed是什么二、sed的常用操作选项三、如何使用sed1.Sed结合正则表达式输出指定行2.增加内容3.删除4.替换5.搜索替换6.插入文件7.另存为到文件8.同时编辑9.分组操作10.读取完退出11.sed脚本12.sed的高级应用 一、sed是什么 sed 命令是利用脚本来处理文本文件。它可…

Redis的集群的搭建

1、为什么要搭建Redis集群 Redis 集群能够提供高可用性、高性能、扩展性和数据安全性&#xff0c;适用于各种需要高速缓存和数据存储的复杂应用场景 2、Redis的集群模式 主从模式哨兵模式区中心化模式 3、主从模式 redis主从模式表示一个主节点跟若干个从节点。主节点可以…

VMware 上安装 CentOS 7 教程 (包含网络设置)

**建议先看一些我安装VMware的教程&#xff0c;有些网络配置需要做一下 1.打开VMware&#xff0c;创建虚拟机 2.勾选自定义&#xff0c;点击下一步 3.点击下一步 4.勾选“稍后安装操作系统”&#xff0c;点击下一步 5.勾选linux&#xff0c;勾选centos7&#xff0c;点击下一步…