使用aiohttp库实现异步爬虫进行优化

在日常爬虫工作中,我们经常使用requests库去爬取某个站点的数据,但是每发出一个请求,程序必须等待网站返回响应才能接着运行,而在整个爬虫过程中爬虫程序是一直在等待的,实际上没有做任何事情。像这种占用磁盘/内存IO、网络IO的任务,大部分时间是CPU在等待的操作,就叫IO密集型任务。对于这种情可以考虑使用aiohttp库实现异步爬虫进行优化。
这篇文章我们详细介绍aiohttp库的用法和爬取实战。aiohttp 是一个支持异步请求的库,它和 asyncio 配合使用,可以使我们非常方便地实现异步请求操作。aiohttp请求的方法和之前有明显区别,主要包括如下几点:

  1. 除了导入aiohttp库,还必须引入asyncio库,因为要实现异步,需要启动协程。
  2. 异步的方法定义不同,前面都要统一加async来修饰。
  3. with as用于声明上下文管理器,帮我们自动分配和释放资源,加上async代码支持异步。
    在一些大型数据爬虫中,对并发的要求很高,而aiohttp可以支持非常高的并发量,但面对高并发网站可能会承受不住,随时有挂掉的危险,这时需要对并发进行一些控制。比如这里我们使用aiohttp来爬取新闻微博数据,因为目标网站反爬机制比较严,所以需要爬取过程中需要加上不同的代理IP和header,实例如下

导入相关库

import asyncio
import aiohttp
from aiohttp_socks import ProxyConnector
import random

定义目标网站和代理服务器的列表

urls = ["weibo.com/?sudaref=www.baidu.com"
proxies = ["socks5://16yun:16ip@www.16yun.cn:8888", "socks5://16yun:16ip@www.16yun.cn:11111", "socks5://username:password@host3:port3"]

定义用户代理的列表

user_agents = [
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 11_6_1) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.2 Safari/605.1.15",
"Mozilla/5.0 (iPhone; CPU iPhone OS 15_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15 Mobile/15E148 Safari/604.1"
]

定义异步函数来发送GET请求,并使用不同的代理服务器和头部来连接目标网站

async def fetch(url):
try:
# 随机选择一个代理服务器和一个用户代理
proxy = random.choice(proxies)
user_agent = random.choice(user_agents)

    # 创建一个aiohttp_socks.ProxyConnector对象,用来设置代理服务器的参数    
    connector = ProxyConnector.from_url(proxy)
    
    # 创建一个字典,用来设置头部参数    
    headers = {"User-Agent": user_agent}
    
    # 创建并启动一个aiohttp.ClientSession对象,用来发送HTTP请求,并传入connector和headers参数    
    async with aiohttp.ClientSession(connector=connector, headers=headers) as session:
        async with session.get(url) as response:
            # 检查响应状态码是否为200,否则抛出异常
            if response.status != 200:
                raise Exception(f"Bad status code: {response.status}")
            # 返回响应内容的文本格式
            return await response.text()
            
        # 在每次请求之后关闭会话    
        await session.close()
        
except Exception as e:
    # 打印异常信息,并返回None
    print(e)
    return None

定义异步主函数来创建并运行多个协程任务,并控制并发数量和超时时间等参数

async def main():
# 创建一个空列表,用来存储所有的协程任务
tasks = []
# 循环遍历目标网站列表,每次创建一个fetch函数的协程任务,并添加到列表中
for url in urls:
task = asyncio.create_task(fetch(url))
tasks.append(task)

# 使用asyncio.gather函数来收集并执行所有的协程任务,并返回一个包含所有结果的列表        
results = await asyncio.gather(*tasks)

# 打印结果列表    
print(results)

在程序入口处调用异步主函数,并启动事件循环

if name == "main":
asyncio.run(main())

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容