非带宽受限场景下如何用Python快速下载大量小文件?
明确结论
requests替代方案完全可行,只需要同步已登录浏览器的Cookie即可继承身份权限,无需浏览器也能访问公司内部网络- 多Driver实例、单Driver多标签页两种方案都可以解决当前的请求串行阻塞问题
方案1:requests复用Cookie(性能最优,推荐优先尝试)
当前你无法用requests直接访问公司网络,本质是缺少浏览器登录后生成的身份校验Cookie,你可以直接从已完成登录的ChromeDriver中导出Cookie注入requests会话,即可绕过身份校验。该方案没有浏览器的额外开销,多线程请求完全并行,50个请求总耗时仅需10秒左右。
示例代码:
import requests from selenium import webdriver from multiprocessing.pool import ThreadPool # 原有登录逻辑 driver = webdriver.Chrome() Login(driver) # 导出浏览器Cookie到requests会话 session = requests.Session() for cookie in driver.get_cookies(): session.cookies.set(cookie["name"], cookie["value"], domain=cookie["domain"]) # 同步浏览器的User-Agent避免被拦截 headers = {"User-Agent": driver.execute_script("return navigator.userAgent")} session.headers.update(headers) # 完成Cookie同步后即可关闭浏览器 driver.quit() def getFile(item): resp = session.get(url.format(item), timeout=30) # 保存CSV到本地 with open(f"{item}.csv", "wb") as f: f.write(resp.content) updateSet = [...] # 你的参数列表 # 并发数设置为10即可,避免过高被网关限流 pool = ThreadPool(10) pool.map(getFile, updateSet) pool.close() pool.join()
如果接口没有额外的JS签名、浏览器指纹校验,该方案可以直接使用。
方案2:多Driver实例并行(兼容性最好,实现简单)
如果有浏览器指纹校验无法用requests,你可以直接初始化少量ChromeDriver实例(不需要多进程,单进程即可运行),每个线程绑定独立的Driver,避免Selenium单实例串行执行命令的问题。普通1核2G的虚拟服务器可以轻松支撑8-10个headless Chrome实例运行,完全符合你的部署要求。
示例代码:
from multiprocessing.pool import ThreadPool from selenium import webdriver # 初始化Driver池,例如开8个并行实例 DRIVER_COUNT = 8 driver_pool = [] for _ in range(DRIVER_COUNT): driver = webdriver.Chrome() Login(driver) # 每个实例完成登录,也可以导入Cookie避免重复登录 driver_pool.append(driver) def getFile(item): # 按参数哈希分配Driver,避免线程冲突 driver = driver_pool[hash(item) % DRIVER_COUNT] driver.get(url.format(item)) # 补充等待下载完成、文件重命名的逻辑 updateSet = [...] pool = ThreadPool(DRIVER_COUNT) pool.map(getFile, updateSet) pool.close() pool.join() # 执行完成后关闭所有Driver for d in driver_pool: d.quit()
方案3:单Driver多标签页异步处理(资源占用最低)
如果服务器配置极低无法运行多个Driver,可以用单Driver开多个标签页的方案,并行触发导航后轮询标签加载状态,资源占用和单个Driver一致。核心逻辑是提前开好对应并发数的标签,批量触发跳转后轮询每个标签的加载状态,加载完成就处理下载并分配新任务。
原有代码问题说明
你之前的多线程方案阻塞,是因为所有线程共用同一个ChromeDriver实例,Selenium的WebDriver本身是线程不安全的,所有命令会串行排队执行,因此会出现第一个请求处理完才能发起第二个的情况,只要避免多线程共用同一个Driver即可解决。
内容的提问来源于stack exchange,提问作者Evan Hagen
相关产品推荐
相关产品推荐

