第九课:异步爬虫进阶:aiohttp与多线程的技术博客

ops/2025/3/15 12:46:49/

Python爬虫开发中,性能优化始终是一个重要的课题。随着网络数据的爆炸式增长,传统的同步爬虫在面对大量请求时显得力不从心。异步爬虫和多线程技术应运而生,成为提升爬虫性能的关键手段。本文将深入探讨Python异步爬虫进阶技术,重点介绍aiohttp与多线程的结合使用,通过同步与异步请求对比、asyncio事件循环原理、线程池ThreadPoolExecutor以及性能优化技巧等方面,帮助读者掌握高效爬虫的开发技巧。

1. 同步与异步请求对比

同步请求

同步请求是指在发送请求后,程序会阻塞等待响应,直到响应到达后才继续执行后续代码。这种方式在处理少量请求时简单直观,但在处理大量请求时,会导致程序效率低下,因为大量时间被浪费在等待响应上。

import requests# 同步请求方式
def sync_request(url):response = requests.get(url)return response.text# 同步请求多个接口
urls = ['http://example.com/1', 'http://example.com/2', 'http://example.com/3']
results = [sync_request(url) for url in urls]
print(results)
异步请求

异步请求则允许程序在等待响应的同时执行其他任务,通过事件循环调度异步任务,提高程序并发性和响应速度。这在处理大量网络请求时尤为有效。

import asyncio
import aiohttpurls = ['http://example.com/1', 'http://example.com/2', 'http://example.com/3']# 定义异步请求方法
async def async_request(session, url):async with session.get(url) as response:return await response.text()async def main():# 请求多个接口async with aiohttp.ClientSession() as session:tasks = [async_request(session, url) for url in urls]results = await asyncio.gather(*tasks)print(results)asyncio.run(main())

2. asyncio事件循环原理

事件循环简介

事件循环是asyncio库的核心组件,负责调度和执行异步任务。它不断地检查任务队列,当有任务准备好(如I/O操作完成)时,便调度该任务执行。事件循环确保了异步任务的高效并发执行。

工作原理
  • 事件队列:存储所有待处理的任务和事件。
  • 轮询检查:事件循环不断检查事件队列,查看是否有新的事件或任务需要处理。
  • 调度执行:一旦有任务准备好,事件循环调度该任务执行。
  • 非阻塞执行:如果某个任务需要等待(如网络请求),事件循环不会阻塞,而是继续处理其他任务。
示例代码
import asyncioasync def task1():print("Task 1 开始")# 模拟耗时操作await asyncio.sleep(2)print("Task 1 完成")async def task2():print("Task 2 开始")# 模拟耗时操作await asyncio.sleep(1)print("Task 2 完成")async def main():task_1 = asyncio.create_task(task1())task_2 = asyncio.create_task(task2())await asyncio.gather(task_1, task_2)asyncio.run(main())

3. 线程池ThreadPoolExecutor

线程池简介

线程池是一种线程管理技术,通过预先创建一定数量的线程并放入池中,当有任务需要执行时,从池中取出线程执行任务,任务完成后线程归还池中。这减少了线程创建和销毁的开销,提高了程序性能。

ThreadPoolExecutor使用方法
from concurrent.futures import ThreadPoolExecutordef worker(num):print(f"Worker {num} is working")with ThreadPoolExecutor(max_workers=5) as executor:futures = [executor.submit(worker, i) for i in range(10)]for future in futures:# 等待任务完成future.result()
示例代码
import threading
from concurrent.futures import ThreadPoolExecutordef task(n):print(f"Task {n} executed by {threading.current_thread().name}")with ThreadPoolExecutor(max_workers=3) as executor:executor.map(task, range(1, 11))

4. 性能优化技巧

并发请求优化

使用aiohttp和asyncio实现并发请求,可以显著提高爬虫性能。通过创建多个异步任务并同时发送请求,减少等待时间。

import asyncio
import aiohttpasync def fetch(session, url):async with session.get(url) as response:return await response.text()async def main():urls = ['http://example.com/1', 'http://example.com/2', 'http://example.com/3']async with aiohttp.ClientSession() as session:tasks = [fetch(session, url) for url in urls]results = await asyncio.gather(*tasks)print(results)asyncio.run(main())
限制并发量

使用asyncio的Semaphore限制并发量,避免对目标服务器造成过大压力,同时保证程序的稳定性和效率。

import asyncio
import aiohttpCONCURRENCY = 5
semaphore = asyncio.Semaphore(CONCURRENCY)async def fetch(session, url):async with semaphore:async with session.get(url) as response:return await response.text()async def main():urls = ['http://example.com/1', 'http://example.com/2', 'http://example.com/3']async with aiohttp.ClientSession() as session:tasks = [fetch(session, url) for url in urls]results = await asyncio.gather(*tasks)print(results)asyncio.run(main())
多线程与异步结合

在某些场景下,可以结合多线程和异步编程,进一步提升性能。例如,使用线程池处理CPU密集型任务,使用异步处理I/O密集型任务。

import asyncio
import aiohttp
from concurrent.futures import ThreadPoolExecutordef cpu_bound_task(n):# 模拟CPU密集型任务total = 0for i in range(n):total += ireturn totalasync def io_bound_task(session, url):async with session.get(url) as response:return await response.text()async def main():urls = ['http://example.com/1', 'http://example.com/2', 'http://example.com/3']with ThreadPoolExecutor(max_workers=3) as executor:loop = asyncio.get_running_loop()cpu_tasks = [loop.run_in_executor(executor, cpu_bound_task, 10**6) for _ in range(3)]async with aiohttp.ClientSession() as session:io_tasks = [io_bound_task(session, url) for url in urls]cpu_results = await asyncio.gather(*cpu_tasks)io_results = await asyncio.gather(*io_tasks)print(f"CPU results: {cpu_results}")print(f"IO results: {io_results}")asyncio.run(main())

总结

通过本文的介绍,我们深入了解了Python异步爬虫进阶技术,包括同步与异步请求的对比、asyncio事件循环原理、线程池ThreadPoolExecutor的使用以及性能优化技巧。通过结合aiohttp和多线程技术,我们可以构建高效、稳定的爬虫系统,满足大规模数据抓取的需求。希望本文能为读者在Python爬虫开发道路上提供一些有益的参考和启发。

关注我!!🫵 持续为你带来Python相关内容。


http://www.ppmy.cn/ops/165941.html

相关文章

SAP Commerce(Hybris)促销模块(一):优惠券配置

基于Hybris的Backoffice后台管理系统,创建一个基于模板的促销规则,并配置上对应的优惠活动。 架构设计 先从一张架构图说起 Hybris的促销模块,是基于Promotion引擎来实现的,可以通过Backoffice来进行配置。 通过上面的架构图又可…

笔记本电脑开机自动启用自定义电源计划方法

笔记本电脑开机自动启用电源计划方法 **方法一:通过任务计划程序设置(推荐)** 获取电源计划的GUID o 按 Win + S,搜索 cmd,右键选择 以管理员身份运行。 o 输入以下命令查看所有电源计划及其GUID: powercfg /list o 找到你创建的电源计划,记录其GUID(例如:8c5e7fda-e8…

TDengine 使用教程:从入门到实践

TDengine 是一款专为物联网(IoT)和大数据实时分析设计的时序数据库。它能够高效地处理海量的时序数据,并提供低延迟、高吞吐量的性能表现。在本文中,我们将带领大家从 TDengine 的安装、基本操作到一些高级功能,帮助你…

基于SpringBoot实现旅游酒店平台功能十一

一、前言介绍: 1.1 项目摘要 随着社会的快速发展和人民生活水平的不断提高,旅游已经成为人们休闲娱乐的重要方式之一。人们越来越注重生活的品质和精神文化的追求,旅游需求呈现出爆发式增长。这种增长不仅体现在旅游人数的增加上&#xff0…

学习网络安全需要哪些基础?

🍅 点击文末小卡片 ,免费获取网络安全全套资料,资料在手,涨薪更快 学习网络安全,对于想要进入IT行业的朋友们来说是一件非常重要的事情。尤其是在当今社会,互联网已经渗透到工作和生活的方方面面&#xff0…

医院本地化DeepSeek R1对接混合数据库技术实战方案研讨

1. 引言 Deep SEEK R1是一个医疗智能化平台,通过本地化部署实现数据的安全性和可控性,同时提供高效的计算能力。随着医疗信息化的迅速发展,各种数据源的增加使得医院面临更多复杂的挑战,包括如何处理实时监测数据、如何进行大数据环境下的复杂查询以及如何整合多模态数据等…

【AIGC】计算机视觉-YOLO系列家族

YOLO系列家族 (1)YOLO发展史(2) YOLOX(3) YOLOv6(4) YOLOv7(5) YOLOv8(6) YOLOv9(7)YOLOv10(8&…

【量化策略】趋势跟踪策略

【量化策略】趋势跟踪策略 🚀量化软件开通 🚀量化实战教程 技术背景与应用场景 在金融市场中,趋势跟踪策略是一种基于市场趋势进行交易的量化投资方法。该策略的核心思想是“顺势而为”,即认为市场价格会沿着一定的方向持续移…