爬虫是Python最经典的用途之一。但很多人写的爬虫效率极低,sequential的请求方式浪费了大量的等待时间。今天我来分享如何用异步编程把爬虫性能提升10倍以上。
问题:传统爬虫的瓶颈
同步爬虫的问题是:每次请求都要等待服务器响应,CPU大部分时间都在空转。如果每个请求平均耗时1秒,10个URL就需要10秒。
解决方案:asyncio + aiohttp
Python 3.4引入了asyncio模块,3.5加入了async/await语法,让异步编程变得简单。配合aiohttp库,我们可以写出高性能的异步爬虫。
import asyncio
import aiohttp
async def fetch_url(session, url):
async with session.get(url) as response:
return await response.text()
async def main():
urls = ["https://example.com/page/{}".format(i) for i in range(1, 11)]
connector = aiohttp.TCPConnector(limit=10)
async with aiohttp.ClientSession(connector=connector) as session:
tasks = [fetch_url(session, url) for url in urls]
results = await asyncio.gather(*tasks)
return results
if __name__ == "__main__":
asyncio.run(main())
进阶:带重试机制和限流的爬虫
实际生产环境需要更完善的错误处理。完整的实现包括:信号量限流、指数退避重试、随机抖动、完整的错误处理。
性能对比
| 方式 | URL数量 | 总耗时 |
|---|---|---|
| 同步requests | 20 | 20.5s |
| 异步aiohttp | 20 | 1.3s |
15倍的性能提升!
完整代码
完整代码和更多示例可以在我的博客找到。
原文发表于 WDSEGA Blog