You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

异步爬虫性能未达预期?asyncio+aiohttp请求有效性排查求助

异步爬虫性能未达预期的排查求助

我编写了一个爬虫脚本,同步请求约30个URL时总耗时95秒。为提升速度,使用asyncio和aiohttp重写了脚本,32次请求的性能统计如下:

  • 同步请求总耗时:95秒
  • 异步请求总耗时:60秒
  • 浏览器手动单次请求URL耗时:约1秒

这个仅50%的速度提升完全达不到预期——按单次请求1秒计算,32次异步请求应该几乎同时发起,总耗时不应超过1.5秒。我怀疑请求并未真正异步执行(刚接触asyncio),希望得到排查方向的提示。

附上我的代码:

# 单个异步请求函数
async def async_get_course(session, url_course):
    async with session.get(url_course) as res:
        response = await res.content.read() 
        return response

# 主协程函数
async def example(courses, root):
    starting_time = time.time()
    
    actions = []
    data = []
    data2 = []
    async with aiohttp.ClientSession() as session:
        for course in courses:
            url_course = f"{root}{course['course_link']}"
            data.append(url_course)
            actions.append(asyncio.ensure_future(async_get_course(session, url_course)))
        results = await asyncio.gather(*actions)
        
        for idx, res in enumerate(results):
            data2.append(get_info_from_course((courses[idx], data[idx], res)))

    total_time = time.time() - starting_time
    print('总耗时', total_time)

    return data2

# 运行协程
courses_final = asyncio.run(example(courses, root))

排查方向提示

  • 检查同步阻塞操作:
    确认get_info_from_course函数是否为同步阻塞——如果该函数包含CPU密集操作或同步IO(如文件读写、同步数据库调用),会在asyncio.gather完成后依次阻塞执行,拖慢总耗时。同时检查async_get_course内部是否有隐藏的同步代码。

  • 调整aiohttp连接池限制:
    aiohttp的ClientSession默认对同一域名的并发连接数有限制,可能导致请求排队。可以显式设置更大的单域名并发数验证:

    connector = aiohttp.TCPConnector(limit_per_host=32) # 匹配请求数量
    async with aiohttp.ClientSession(connector=connector) as session:
        # 原有逻辑
    
  • 验证请求并发状态:
    在async_get_course中添加日志,打印每个请求的开始/结束时间,确认是否所有请求几乎同时发起:

    import logging
    logging.basicConfig(level=logging.INFO)
    
    async def async_get_course(session, url_course):
        logging.info(f"开始请求: {url_course}")
        async with session.get(url_course) as res:
            response = await res.content.read() 
            logging.info(f"完成请求: {url_course}")
            return response
    
  • 排查目标网站限流:
    目标服务器可能对同一IP的并发请求做了限流,即使异步发起也会被排队处理。可以尝试用多IP代理测试,或对比浏览器多标签页同时请求的耗时。

  • 检查事件循环是否被阻塞:
    确保代码中没有调用time.sleep()(需替换为await asyncio.sleep()),也没有使用不支持异步的第三方库,这些都会阻塞事件循环导致异步失效。

  • 测试极简异步案例:
    编写只包含异步请求的极简脚本,排除后续处理的影响,看耗时是否正常:

    import asyncio
    import aiohttp
    import time
    
    async def fetch(session, url):
        async with session.get(url) as response:
            return await response.text()
    
    async def main():
        start = time.time()
        # 替换为你的目标URL列表
        urls = [f"{root}{course['course_link']}" for course in courses]
        connector = aiohttp.TCPConnector(limit_per_host=32)
        async with aiohttp.ClientSession(connector=connector) as session:
            tasks = [fetch(session, url) for url in urls]
            await asyncio.gather(*tasks)
        print(f"纯请求总耗时: {time.time() - start}")
    
    asyncio.run(main())
    

    如果这个脚本耗时符合预期,说明问题出在get_info_from_course的处理环节。

内容的提问来源于stack exchange,提问作者LLaP

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 05:47:45