Python编程异步爬虫——aiohttp的使用

简介: Python编程异步爬虫——aiohttp的使用

异步爬虫—aiohttp的使用
1.基本介绍
asyncio模块其内部实现了对TCP、UDP、SSL协议的异步操作,但是对于HTTP请求来说,就需要用aiohttp实现了。
aiohttp是一个基于asyncio的异步HTTP网络模块,它既提供了服务端,又提供了客户端。requests发起的是同步网络请求,aiohttp则是异步。 aiohttp 模块是一个基于 asyncio 的 HTTP 客户端和服务器框架,可以用于异步处理 HTTP 请求和响应。以下是一个简单的示例代码展示 aiohttp 模块的基本用法:

首先,你需要安装 aiohttp 模块:

pip install aiohttp

2.基本示例
接下来,以下是一个简单的示例代码,演示了如何使用 aiohttp 发送一个简单的 GET 请求并获取响应:

import aiohttp
import asyncio

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

在这个示例中,我们定义了一个 fetch 函数来发送 GET 请求并返回响应文本,然后使用 main 函数调用 fetch 函数。最后,创建事件循环并运行主函数。

由于网页源码过长,这里只截取了输出的一部分,可以看到,成功获取了网页的源代码及响应状态码200,成功使用aiohttp通过异步方式完成了网页爬取。当然,这个操作用requests也可以做到。

3.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('https://www.httpbin.org/get', params=params) as response:
            print(await response.text())

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


  运行结果如下:
  {
   
  "args": {
   
    "age": "25", 
    "name": "germey"
  }, 
  "headers": {
   
    "Accept": "*/*", 
    "Accept-Encoding": "gzip, deflate", 
    "Host": "www.httpbin.org", 
    "User-Agent": "Python/3.9 aiohttp/3.8.3", 
    "X-Amzn-Trace-Id": "Root=1-65ffa6c9-6d501fa57391d9fc1d7b5f28"
  }, 
  "origin": "58.21.224.175", 
  "url": "https://www.httpbin.org/get?name=germey&age=25"
}

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

4.其他请求类型
aiohttp还支持其他请求类型,如POST、PUT、DELETE等,这和requests的使用方式有点类似,示例如下:

session.post('http://www.httpbin.org/post', data=b'data')
session.put('http://www.httpbin.org/put', data=b'data')
session.delete('http://www.httpbin.org/delete')
session.head('http://www.httpbin.org/get')
session.options('http://www.httpbin.org/get')
session.patch('http://www.httpbin.org/patch', data=b'data')

5.POST请求
当使用 aiohttp 模块时,除了发送简单的 GET 请求之外,你还可以处理 POST 请求、设置请求头、处理异常等。以下是一个稍微复杂一点的示例代码,展示了如何发送 POST 请求并处理异常:

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.get_event_loop().run_until_complete(main())


   运行结果如下:
   {
   
  "args": {
   }, 
  "data": "", 
  "files": {
   }, 
  "form": {
   
    "age": "25", 
    "name": "germey"
  }, 
  "headers": {
   
    "Accept": "*/*", 
    "Accept-Encoding": "gzip, deflate", 
    "Content-Length": "18", 
    "Content-Type": "application/x-www-form-urlencoded", 
    "Host": "www.httpbin.org", 
    "User-Agent": "Python/3.9 aiohttp/3.8.3", 
    "X-Amzn-Trace-Id": "Root=1-65ffabc5-3bbf3cdb7cb413a3475ece45"
  }, 
  "json": null, 
  "origin": "58.21.224.175", 
  "url": "https://www.httpbin.org/post"
}

在上面的示例中,我们定义了一个 fetch 函数来发送一个包含 JSON 数据的 POST 请求,并在发生异常时进行处理。在 main 函数中调用 fetch 函数,并根据返回的状态码和响应文本输出相应信息。

通过这个示例,你可以进一步了解如何使用 aiohttp 模块处理 POST 请求和异常情况。你可以根据自己的需求进行进一步的定制和扩展。希望这能帮助你更深入地理解 aiohttp 模块的用法。

对于POST J SON数据提交,其对应的请求头中的Content-Type为application/json,我们只需将post方法里的data参数改成json即可,实例代码如下:

import 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__':
    print(asyncio.get_event_loop().run_until_complete(main()))

运行结果如下:
    {
   
  "args": {
   }, 
  "data": "{\"name\": \"germey\", \"age\": 25}", 
  "files": {
   }, 
  "form": {
   }, 
  "headers": {
   
    "Accept": "*/*", 
    "Accept-Encoding": "gzip, deflate", 
    "Content-Length": "29", 
    "Content-Type": "application/json", 
    "Host": "www.httpbin.org", 
    "User-Agent": "Python/3.9 aiohttp/3.8.4", 
    "X-Amzn-Trace-Id": "Root=1-65ffc207-7d035c6f2b342778797881c9"
  }, 
  "json": {
   
    "age": 25, 
    "name": "germey"
  }, 
  "origin": "58.21.224.175", 
  "url": "https://www.httpbin.org/post"
}

6.响应
我们可以用如下方法分别获取其中的状态码、响应头、响应体、响应体二进制内容、响应体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.get_event_loop().run_until_complete(main())

运行结果如下:
status: 200
headers: <CIMultiDictProxy('Date': 'Sun, 24 Mar 2024 06:34:54 GMT', 'Content-Type': 'application/json', 'Content-Length': '510', '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", 
    "Content-Length": "18", 
    "Content-Type": "application/x-www-form-urlencoded", 
    "Host": "www.httpbin.org", 
    "User-Agent": "Python/3.9 aiohttp/3.8.4", 
    "X-Amzn-Trace-Id": "Root=1-65ffc98e-153aad5f0e536d773cd978b4"
  }, 
  "json": null, 
  "origin": "58.21.224.175", 
  "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", \n    "Content-Length": "18", \n    "Content-Type": "application/x-www-form-urlencoded", \n    "Host": "www.httpbin.org", \n    "User-Agent": "Python/3.9 aiohttp/3.8.4", \n    "X-Amzn-Trace-Id": "Root=1-65ffc98e-153aad5f0e536d773cd978b4"\n  }, \n  "json": null, \n  "origin": "58.21.224.175", \n  "url": "https://www.httpbin.org/post"\n}\n'
json: {
   'args': {
   }, 'data': '', 'files': {
   }, 'form': {
   'age': '25', 'name': 'germey'}, 'headers': {
   'Accept': '*/*', 'Accept-Encoding': 'gzip, deflate', 'Content-Length': '18', 'Content-Type': 'application/x-www-form-urlencoded', 'Host': 'www.httpbin.org', 'User-Agent': 'Python/3.9 aiohttp/3.8.4', 'X-Amzn-Trace-Id': 'Root=1-65ffc98e-153aad5f0e536d773cd978b4'}, 'json': None, 'origin': '58.21.224.175', 'url': 'https://www.httpbin.org/post'}

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

7.超时设置
我们可以借助ClientTimeout对象设置超时,例如要设置1秒的超时时间,可以这么实现:

import asyncio
import aiohttp

async def main():
    timeout = aiohttp.ClientTimeout(total=2)
    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())

运行结果如下:
200

8.并发限制
由于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(100000)]
    await asyncio.gather(*scrape_index_tasks)

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

运行结果:
scraping https://www.baidu.com
scraping https://www.baidu.com
scraping https://www.baidu.com
scraping https://www.baidu.com
scraping https://www.baidu.com
....

这里我们声明CONCURRENCY(代表爬取的最大并发量)为5, 同时声明爬取的目标URL为百度。接着,借助Semaphore创建了一个信号量对象,将其赋值为semaphore,这样就可以用它来控制最大并发量了。这里我们把semaphore直接放置在了对应的爬取方法里,使用async with语句将semaphore作为上下文对象即可。信号量便可以控制进入爬取的最大协程数量,即我们声明的CONCURRENCY的值。在main方法里, 我们声明10 000个task,将其传递给gather方法运行,倘若不加以限制,那这10000个task会被同时执行,并发数量相当大。有了信号量的控制后,同时运行的task数量最大会被控制5个,这样就能给aiohttp限制速度了。

相关文章
|
1天前
|
Python
不容错过!Python中图的精妙表示与高效遍历策略,提升你的编程艺术感
本文介绍了Python中图的表示方法及遍历策略。图可通过邻接表或邻接矩阵表示,前者节省空间适合稀疏图,后者便于检查连接但占用更多空间。文章详细展示了邻接表和邻接矩阵的实现,并讲解了深度优先搜索(DFS)和广度优先搜索(BFS)的遍历方法,帮助读者掌握图的基本操作和应用技巧。
13 4
|
1天前
|
设计模式 程序员 数据处理
编程之旅:探索Python中的装饰器
【10月更文挑战第34天】在编程的海洋中,Python这艘航船以其简洁优雅著称。其中,装饰器作为一项高级特性,如同船上的风帆,让代码更加灵活和强大。本文将带你领略装饰器的奥秘,从基础概念到实际应用,一起感受编程之美。
|
1天前
|
Python
Python中的异步编程:使用asyncio和aiohttp实现高效网络请求
【10月更文挑战第34天】在Python的世界里,异步编程是提高效率的利器。本文将带你了解如何使用asyncio和aiohttp库来编写高效的网络请求代码。我们将通过一个简单的示例来展示如何利用这些工具来并发地处理多个网络请求,从而提高程序的整体性能。准备好让你的Python代码飞起来吧!
|
1天前
|
机器学习/深度学习 JSON API
Python编程实战:构建一个简单的天气预报应用
Python编程实战:构建一个简单的天气预报应用
10 1
|
1天前
|
算法 Python
在Python编程中,分治法、贪心算法和动态规划是三种重要的算法。分治法通过将大问题分解为小问题,递归解决后合并结果
在Python编程中,分治法、贪心算法和动态规划是三种重要的算法。分治法通过将大问题分解为小问题,递归解决后合并结果;贪心算法在每一步选择局部最优解,追求全局最优;动态规划通过保存子问题的解,避免重复计算,确保全局最优。这三种算法各具特色,适用于不同类型的问题,合理选择能显著提升编程效率。
15 2
|
2天前
|
SQL 数据挖掘 Python
数据分析编程:SQL,Python or SPL?
数据分析编程用什么,SQL、python or SPL?话不多说,直接上代码,对比明显,明眼人一看就明了:本案例涵盖五个数据分析任务:1) 计算用户会话次数;2) 球员连续得分分析;3) 连续三天活跃用户数统计;4) 新用户次日留存率计算;5) 股价涨跌幅分析。每个任务基于相应数据表进行处理和计算。
|
8天前
|
数据采集 存储 JSON
Python网络爬虫:Scrapy框架的实战应用与技巧分享
【10月更文挑战第27天】本文介绍了Python网络爬虫Scrapy框架的实战应用与技巧。首先讲解了如何创建Scrapy项目、定义爬虫、处理JSON响应、设置User-Agent和代理,以及存储爬取的数据。通过具体示例,帮助读者掌握Scrapy的核心功能和使用方法,提升数据采集效率。
46 6
|
3月前
|
机器学习/深度学习 数据采集 数据可视化
基于爬虫和机器学习的招聘数据分析与可视化系统,python django框架,前端bootstrap,机器学习有八种带有可视化大屏和后台
本文介绍了一个基于Python Django框架和Bootstrap前端技术,集成了机器学习算法和数据可视化的招聘数据分析与可视化系统,该系统通过爬虫技术获取职位信息,并使用多种机器学习模型进行薪资预测、职位匹配和趋势分析,提供了一个直观的可视化大屏和后台管理系统,以优化招聘策略并提升决策质量。
167 4
|
3月前
|
数据采集 存储 搜索推荐
打造个性化网页爬虫:从零开始的Python教程
【8月更文挑战第31天】在数字信息的海洋中,网页爬虫是一艘能够自动搜集网络数据的神奇船只。本文将引导你启航,用Python语言建造属于你自己的网页爬虫。我们将一起探索如何从无到有,一步步构建一个能够抓取、解析并存储网页数据的基础爬虫。文章不仅分享代码,更带你理解背后的逻辑,让你能在遇到问题时自行找到解决方案。无论你是编程新手还是有一定基础的开发者,这篇文章都会为你打开一扇通往数据世界的新窗。
|
4月前
|
数据采集 存储 JSON
从零到一构建网络爬虫帝国:HTTP协议+Python requests库深度解析
【7月更文挑战第31天】在网络数据的海洋中,使用Python的`requests`库构建网络爬虫就像探索未知的航船。HTTP协议指导爬虫与服务器交流,收集信息。HTTP请求包括请求行、头和体,响应则含状态行、头和体。`requests`简化了发送各种HTTP请求的过程。
82 4
下一篇
无影云桌面