使用Dask+Requests爬虫:4核仅获2倍提速的原因解析
为什么你的Dask代码只实现了2倍速度提升(而非4倍)?
看起来你碰到了Dask并行化场景里很常见的IO瓶颈问题,结合网页抓取的场景,我梳理了几个核心原因和对应的解决方案:
核心原因分析
1. 网络IO是真正的瓶颈,而非CPU
你的scrape函数里,最耗时的步骤是requests.get()——这是同步阻塞的网络请求。当Dask启动4个并发任务时,大部分时间CPU都在等待网站的响应,根本没在做计算。如果目标网站对同一IP的并发请求做了限制(比如只允许同时处理2个请求),那即使你开了4个worker,实际也只能同时跑2个任务,自然只有2倍提速。
2. Dask默认执行器的潜在限制
Dask的delayed默认使用线程执行器(dask.threaded.get),线程数默认是cpu_count()也就是4,但如果你的网络请求因为网站限流、DNS解析慢或者TCP连接开销大,线程再多也没法突破速度上限。另外,如果你之前修改过Dask的全局配置,也可能导致worker数量被意外限制。
3. 代码里的冗余操作(不影响提速,但可以优化)
顺便提一句,你的代码里有一行完全冗余的代码:
prods = [prod.text for prod in prods]
这行是重复处理已经提取过text的列表,删掉它不影响功能,还能省点微小的资源。
解决方案
方案1:控制并发请求数,适配网站限制
如果是网站限流导致的,你可以显式指定Dask的worker数量,或者给请求加小延迟,避免触发反爬机制:
# 在compute时指定worker数量,先从2个开始测试,再逐步调整 df = df.compute(scheduler='threads', num_workers=2) # 或者给scrape函数加短延迟,降低请求频率 import time def scrape(id): time.sleep(0.5) # 加500ms延迟,避免被网站限流 page = id+1 start = 40*page bs = BeautifulSoup(requests.get(base_url.format(start,page)).text,'lxml') # ... 后续代码不变
方案2:改用异步请求库(更适合IO密集型抓取)
对于网页抓取这种IO密集型任务,异步请求(比如aiohttp)比同步的requests效率高很多,能更充分利用CPU的空闲时间。结合Dask的异步执行器,能最大化并发能力:
import aiohttp import asyncio async def async_scrape(id): page = id+1 start = 40*page async with aiohttp.ClientSession() as session: async with session.get(base_url.format(start,page)) as resp: text = await resp.text() bs = BeautifulSoup(text,'lxml') prods = [prod.text for prod in bs.find_all('span',attrs={'class':'product-description js-ellipsis'})] brands = [b.text for b in bs.find_all('span',attrs={'class':'product-name'})] return pd.DataFrame({'product': prods, 'brand': brands}) # 用Dask的异步执行器运行 data = [dask.delayed(async_scrape)(id) for id in range(10)] df = dask.delayed(pd.concat)(data) df = df.compute(scheduler='asyncio', num_workers=4)
方案3:复用HTTP连接
用requests.Session()来复用TCP连接,减少每次请求的握手开销,提升整体速度:
# 提前创建session,传给scrape函数 session = requests.Session() def scrape(id, session): page = id+1 start = 40*page bs = BeautifulSoup(session.get(base_url.format(start,page)).text,'lxml') # ... 后续代码不变 data = [dask.delayed(scrape)(id, session) for id in range(10)]
内容的提问来源于stack exchange,提问作者Sergio Lucero
相关产品推荐
相关产品推荐

