提高 Python 爬虫并发效率最推荐的做法是使用 aiohttp 库配合 asyncio.Semaphore 控制并发量。适用场景为 IO 密集型任务,风险边界在于目标站点反爬策略和本地连接数限制。
先说结论:使用异步 IO 库替代同步请求,并通过信号量限制最大并发连接数。
- 先定位:确认任务属于网络 IO 等待耗时大于 CPU 计算耗时的场景。
- 先做:安装
aiohttp并在代码中引入asyncio.Semaphore限制并发。 - 再验证:对比总耗时变化,监控目标服务器返回的状态码是否正常。
快速处理思路
如果不方便直接运行命令,可参考以下最小可用代码结构,将同步请求替换为异步会话。
import aiohttp
import asyncio
async def fetch(session, url, semaphore):
async with semaphore:
async with session.get(url) as response:
return await response.text()
async def main(urls):
semaphore = asyncio.Semaphore(10) # 限制并发数为 10
async with aiohttp.ClientSession() as session:
tasks = [fetch(session, url, semaphore) for url in urls]
await asyncio.gather(*tasks)
# asyncio.run(main(url_list))为什么会这样
异步并发能提升效率的核心原因是避免了线程在等待网络响应时的空闲浪费。
Python 的 asyncio 基于事件循环(Event Loop)机制,当单个请求等待服务器响应时,事件循环会切换到其他就绪的任务继续执行。相比多线程,异步 IO 在上下文切换上的开销更低,适合高并发网络请求场景。但如果是 CPU 密集型计算,异步方案无法利用多核优势,效率不会提升。
分步处理
按以下步骤将同步爬虫改造为异步并发,每步完成后需检查代码逻辑。
步骤 1:安装依赖
在虚拟环境中安装 aiohttp,避免污染全局环境。
pip install aiohttp步骤 2:重构请求函数
将 requests.get 替换为 session.get,并在函数定义前加 async 关键字。确保函数内部所有 IO 操作都使用了 await,否则会导致事件循环阻塞。
步骤 3:添加并发控制
实例化 asyncio.Semaphore 对象,并在请求代码块外层使用 async with 包裹。并发数建议从 10 开始测试,根据目标服务器承受能力调整。
步骤 4:启动事件循环
使用 asyncio.run() 作为程序入口。Python 3.7 及以上版本支持此方法,旧版本需使用 get_event_loop()。
怎么验证是否生效
通过记录起止时间和检查日志确认并发效果及稳定性。
检查耗时:在 main 函数包裹 time.time() 计算总耗时。相同 URL 列表下,异步总耗时应显著小于同步串行耗时。
检查状态:在 fetch 函数中打印 response.status。确认大量并发下没有出现频繁的 429(Too Many Requests)或 503 错误。
检查资源:使用系统监控工具观察本地网络连接数。确认连接数未超过操作系统文件描述符限制。
常见坑
以下错误会导致异步代码退化为串行或引发运行时异常。
在异步函数中调用同步库:如果在 async def 中使用了 requests 或 time.sleep,会阻塞整个事件循环。必须使用 aiohttp 和 asyncio.sleep。
未关闭会话:aiohttp.ClientSession 必须使用 async with 上下文管理器或显式调用 close(),否则会导致资源泄漏警告。
忽略异常处理:网络请求容易超时或失败。需在 fetch 函数内使用 try...except 捕获 aiohttp.ClientError,避免单个失败导致 asyncio.gather 抛出异常中断所有任务。
常见问题
异步爬虫能比多线程快多少?
公开资料中没有看到可靠的量化数据,具体提升取决于网络延迟和目标服务器响应速度。
Semaphore 并发数设置多少合适?
没有固定标准,建议从 10 开始逐步增加,直到观察到目标服务器返回错误码或本地网络出现丢包。
可以在异步代码中使用 pandas 处理数据吗?
可以,但 pandas 是同步库,数据处理过程会阻塞事件循环。建议在数据抓取完成后统一处理,或使用进程池 offload 计算任务。
参考来源
Python asyncio 文档:https://docs.python.org/3/library/asyncio.html
aiohttp 官方文档:https://docs.aiohttp.org/