设计方案
- 任务队列:将需要爬取的网页URL放入任务队列中。
- 异步请求:使用
aiohttp
库发送异步HTTP请求获取网页内容。
- 限制并发数:通过
asyncio.Semaphore
控制同时进行的请求数量,避免资源耗尽。
- 数据处理:爬取到网页内容后,进行复杂的解析和数据处理。
- 错误处理:对请求和数据处理过程中的异常进行捕获和处理,防止死锁等问题。
关键代码示例
import asyncio
import aiohttp
async def fetch(session, url, semaphore):
async with semaphore:
try:
async with session.get(url) as response:
html = await response.text()
# 在这里进行复杂的解析和数据处理
process_data(html)
return html
except Exception as e:
print(f"Error fetching {url}: {e}")
async def main(urls):
semaphore = asyncio.Semaphore(100) # 限制并发数为100
async with aiohttp.ClientSession() as session:
tasks = [fetch(session, url, semaphore) for url in urls]
await asyncio.gather(*tasks)
def process_data(html):
# 模拟复杂的数据处理
pass
if __name__ == "__main__":
# 假设这里有数千个网页的URL
urls = ["http://example.com" for _ in range(10000)]
asyncio.run(main(urls))
性能优化点解释
- 异步请求:
aiohttp
库使用异步I/O,在等待网络响应时不会阻塞主线程,从而提高整体效率。
- 限制并发数:通过
asyncio.Semaphore
设置并发数,避免过多的请求占用过多系统资源(如文件描述符、内存等),防止资源耗尽。
- 错误处理:在
fetch
函数中捕获异常,避免因某个请求失败而导致整个任务队列无法继续执行,从而避免死锁。
- 任务并发执行:使用
asyncio.gather
并发执行所有任务,充分利用系统资源。