标签:#Python爬虫 #aiohttp异步爬虫 #并发请求 #高性能爬虫 #爬虫提速优化
前言
截止上一篇,我们掌握了全套常规爬虫技能:静态解析、动态渲染、批量分页、数据存储、反爬突破、完整项目实战。
但所有基于 requests 的爬虫,都有一个致命短板:同步串行执行。
简单说就是:一次只能请求一个页面,必须等上一个请求结束、响应返回,才能执行下一次请求。
如果需要爬取几十、上百条数据,串行爬取耗时会成倍叠加,速度极慢、效率极低,完全无法满足批量采集需求。
想要突破爬虫速度瓶颈,必须解锁异步并发爬虫!
本篇详解爬虫高性能核心组合:asyncio + aiohttp,利用IO多路复用,在网络等待间隙并发发起多个请求,爬虫速度直接提升数十倍甚至上百倍,零基础也能轻松拿捏工业级高性能爬虫!
一、同步VS异步爬虫:零基础通俗对比
1、同步爬虫(requests)
执行逻辑:排队执行,串行等待
请求1 → 等待响应 → 请求2 → 等待响应 → 请求3...
缺点:大量时间浪费在「网络等待」,CPU全程闲置,资源浪费、速度极慢
2、异步爬虫(aiohttp)
执行逻辑:异步挂起,并发执行
同时发起多个请求,等待某一个请求响应时,程序自动去执行其他任务,不阻塞、不排队
优势:榨干网络与CPU性能,海量链接批量爬取,效率碾压同步爬虫
二、环境一键安装
aiohttp是Python专用异步网络请求库,需手动安装,终端执行豆瓣源加速安装命令:
pip install aiohttp -i https://pypi.douban.com/simple/配套依赖说明
✅ asyncio:Python内置异步事件循环库,无需安装,负责管理异步任务
✅ aiohttp:异步网络请求核心库,替代同步requests
✅ aiohttp.ClientSession:异步会话对象,等同于requests.Session,全局复用更稳定
三、异步核心关键字(零基础必懂)
看懂这4个关键字,彻底入门异步编程,告别看不懂代码的困境:
1. async:修饰普通函数,将其变为异步函数,可被异步调用、可挂起等待
2. await:等待IO任务执行完成(网络请求、文件读取),等待期间不阻塞程序
3. create_task:创建异步任务,加入事件循环,实现并发执行
4. gather:批量收集所有异步任务结果,统一返回数据
四、最简入门:单次异步GET请求(可直接运行)
复刻requests基础请求,用aiohttp实现异步请求,适配浏览器伪装、超时容错,新手入门首选。
import aiohttpimport asyncio# 全局请求头伪装防爬HEADERS = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"}# 异步请求函数async def fetch_single_url(session, url):try:# 异步发起GET请求,设置10秒超时async with session.get(url, headers=HEADERS, timeout=aiohttp.ClientTimeout(total=10)) as resp:html = await resp.text()print(f"✅ 请求成功 状态码:{resp.status}")return htmlexcept Exception as e:print(f"❌ 请求失败:{str(e)}")return None# 异步主函数async def main():# 全局创建异步会话,全程复用(核心!不要重复创建)async with aiohttp.ClientSession() as session:result = await fetch_single_url(session, "https://www.baidu.com")print("页面源码长度:", len(result))# 启动异步程序入口if __name__ == "__main__":asyncio.run(main())
新手核心禁忌:异步IO操作(text/json/read)必须加await,否则无法获取数据、代码直接报错!
五、核心实战:无限制批量并发请求
基于异步任务队列,一次性并发请求多个链接,对比同步爬虫,速度提升数十倍。适合少量链接快速测试。
import aiohttpimport asyncioHEADERS = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"}async def fetch_url(session, url):try:async with session.get(url, headers=HEADERS, timeout=aiohttp.ClientTimeout(total=10)) as resp:html = await resp.text()print(f"✅ 成功爬取:{url} 状态码:{resp.status}")return {"url": url, "html": html, "status": resp.status}except Exception as e:print(f"❌ 爬取失败 {url}:{str(e)}")return {"url": url, "html": None, "status": 0}async def main():# 批量请求链接列表url_list = ["https://www.baidu.com","https://www.qq.com","https://www.sogou.com","https://www.taobao.com"]async with aiohttp.ClientSession() as session:# 批量创建异步任务task_list = [asyncio.create_task(fetch_url(session, url)) for url in url_list]# 等待所有任务执行完成,收集结果all_result = await asyncio.gather(*task_list)# 遍历打印结果for res in all_result:print(f"链接:{res['url']} 源码长度:{len(res['html']) if res['html'] else0}")if __name__ == "__main__":asyncio.run(main())
⚠️ 重要提醒:该方式无并发限制,少量链接可用,大批量爬取禁止使用!瞬间爆发大量请求,极易触发网站反爬、IP封禁。
六、生产级核心:信号量限制并发(必掌握)
真实项目中,必须限制最大并发数,模拟人工平稳访问,规避限流封禁,这是异步爬虫稳定运行的核心!
通过 asyncio.Semaphore 信号量,控制同时运行的请求数量,兼顾速度与稳定性。
import aiohttpimport asyncio# 核心配置:限制最大并发数(根据网站反爬强度调整,一般5-10最佳)MAX_CONCURRENT = 5HEADERS = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"}async def safe_fetch(session, sem, url):# 限制并发:同一时间最多执行MAX_CONCURRENT个任务async with sem:try:async with session.get(url, headers=HEADERS, timeout=aiohttp.ClientTimeout(total=15)) as resp:html = await resp.text()print(f"✅ 爬取完成:{url}")return url, htmlexcept Exception as e:print(f"❌ 爬取异常 {url}:{e}")return url, Noneasync def main():# 在main内部创建信号量(正确写法,绑定当前事件循环)sem = asyncio.Semaphore(MAX_CONCURRENT)# 批量生成15条测试链接url_list = [f"https://www.baidu.com?page={i}" for i in range(1, 16)]async with aiohttp.ClientSession() as session:tasks = [asyncio.create_task(safe_fetch(session, sem, url)) for url in url_list]results = await asyncio.gather(*tasks)print("\n🎉 全部任务执行完成!")# 遍历结果示例# for url, html in results:# if html:# print(f"{url} 页面长度:{len(html)}")if __name__ == "__main__":asyncio.run(main())
参数调试技巧
✅ 普通资讯网站:并发5-10
✅ 风控严格网站:并发2-3,降低请求频率
✅ 测试环境:可适当调高,生产环境保守配置
七、异步POST请求实战(表单/JSON参数)
适配登录接口、数据提交、参数请求场景,覆盖异步爬虫全场景需求。
import aiohttpimport asyncioasync def async_post():url = "https://httpbin.org/post"headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36","Content-Type": "application/json"}# 提交JSON参数post_data = {"username": "spider_test","type": "async_crawl"}async with aiohttp.ClientSession() as session:async with session.post(url, headers=headers, json=post_data) as resp:# 异步解析JSON数据res_data = await resp.json()print("响应数据:", res_data)if __name__ == "__main__":asyncio.run(async_post())
八、异步+数据解析完整实战(可直接项目复用)
整合异步并发请求 + BeautifulSoup数据解析 + 并发限制 + 异常容错,完整复刻工业级爬虫流程。
import aiohttpimport asynciofrom bs4 import BeautifulSoup# 并发限制配置MAX_CONCURRENT = 5HEADERS = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"}# 异步请求+数据解析async def crawl_and_parse(session, sem, url):async with sem:try:async with session.get(url, headers=HEADERS, timeout=aiohttp.ClientTimeout(total=10)) as resp:html = await resp.text()# 同步解析页面soup = BeautifulSoup(html, "lxml")title = soup.title.get_text().strip() if soup.title else "无标题"print(f"✅ 解析成功:{url} | 标题:{title}")return {"url": url, "title": title}except Exception as e:print(f"❌ 解析失败 {url}:{e}")return Noneasync def main():# 信号量必须在main内创建,绑定当前事件循环sem = asyncio.Semaphore(MAX_CONCURRENT)url_list = ["https://www.baidu.com","https://www.qq.com","https://www.sogou.com"]async with aiohttp.ClientSession() as session:tasks = [asyncio.create_task(crawl_and_parse(session, sem, url)) for url in url_list]result_list = await asyncio.gather(*tasks)# 过滤空数据valid_data = [res for res in result_list if res]print(f"\n🎉 批量爬取完成,有效数据{len(valid_data)}条")if __name__ == "__main__":asyncio.run(main())
九、新手高频踩坑汇总(避坑必看)
1、IO操作忘记加await
resp.text()、resp.json() 等网络IO操作,必须加await,否则返回协程对象,无法获取数据。
2、不限制并发数量
大批量爬取无信号量限制,瞬间并发爆炸,直接IP封禁,生产环境绝对禁止!
3、重复创建ClientSession
Session全局创建、全程复用,频繁新建会话会造成资源泄漏、请求不稳定。
4、异步用time.sleep延时
time.sleep()是同步阻塞方法,会卡死整个异步事件循环,异步延时必须用 await asyncio.sleep()。
5、不设置超时时间
部分网页请求卡死无响应,不设置超时会导致整个爬虫任务停滞、卡死。
文末结语
至此,你已经掌握爬虫两大核心体系:同步精准爬取 + 异步高速并发爬取。
requests适合小体量精准采集,aiohttp适合大体量批量高速采集,二者互补,适配所有爬虫场景。
异步爬虫是爬虫进阶的分水岭,也是项目实战、批量采集、数据落地的必备技能,吃透本篇,你的爬虫效率直接进阶工业级!
本篇所有模板代码可直接复制复用,建议收藏,后续所有批量爬虫项目均可直接套用!