
本文详解 selenium 在频繁打开/关闭浏览器标签页时出现内存持续增长的根本原因,并提供基于定期重启 webdriver 实例的稳定、可落地的内存管理策略。
本文详解 selenium 在频繁打开/关闭浏览器标签页时出现内存持续增长的根本原因,并提供基于定期重启 webdriver 实例的稳定、可落地的内存管理策略。
在使用 Selenium 自动化采集网页数据时,若需批量处理数百个 URL(例如通过 window.open() 动态创建标签页),开发者常遇到一个典型瓶颈:即使调用 driver.close() 关闭标签页,chrome 进程的内存占用仍持续攀升,且几乎不释放。如示例代码所示,循环 25 次开闭标签页后,任务管理器中 Chrome 的内存占用可能增长数百 MB——这并非由 Python 端缓存的数据导致,而是 Chromium 渲染进程与 WebDriver 会话间存在资源回收延迟或未完全清理的上下文(如 js 执行环境、网络栈、GPU 缓存等)。driver.close() 仅关闭当前窗口句柄,但底层 Blink 渲染器、V8 实例及部分共享内存区域并未被及时归还操作系统。
✅ 推荐解决方案:分批复用 + 定期重置 WebDriver
最有效、经生产验证的实践是 避免长期持有单个 WebDriver 实例,转而采用「固定批次 + 显式退出 + 重建」策略。例如每处理 20–50 个页面后调用 driver.quit(),再新建实例继续执行。该方式虽引入毫秒级启动开销,却能彻底切断内存累积链路,保障整体稳定性。
以下为优化后的参考实现:
from selenium import webdriver from selenium.webdriver.chrome.options import Options import time def create_driver(): options = Options() options.add_argument("--no-sandbox") options.add_argument("--disable-dev-shm-usage") options.add_argument("--disable-gpu") options.add_argument("--incognito") # 减少扩展/缓存干扰 # 可选:限制内存用量(Chromium 参数) options.add_argument("--memory-pressure-threshold-mb=512") return webdriver.Chrome(options=options) def scrape_batch(urls, batch_size=30): driver = create_driver() base_url = "https://edition.cnn.com/" try: driver.get(base_url) for i, url in enumerate(urls): if i > 0 and i % batch_size == 0: # 每 batch_size 个页面后重置驱动 driver.quit() print(f"✅ Batch {i//batch_size} completed. Restarting WebDriver...") driver = create_driver() driver.get(base_url) # 复用首个 tab,避免频繁 window.open driver.get(url) # ✨ 此处插入您的数据提取逻辑 # e.g., title = driver.title; content = driver.find_element(...).text time.sleep(0.3) # 防反爬节流,非必需 finally: driver.quit() # 确保最终释放 # 使用示例:模拟 600 个目标 URL urls = ["https://edition.cnn.com/"] * 600 scrape_batch(urls, batch_size=40)
⚠️ 关键注意事项
- 不要依赖 window.open() + close() 模拟多标签页:这是内存泄漏的主因。现代 Chromium 对动态标签页的资源隔离不完善,尤其在无用户交互场景下。
- 禁用无关功能:–disable-gpu、–disable-dev-shm-usage 等参数可显著降低基础内存 footprint。
- 避免全局 driver 实例:切勿在整个脚本生命周期内复用同一 driver 对象处理全部请求。
- 监控与兜底:可在循环中加入内存检查(如 psutil.Process().memory_info().rss),超阈值时主动 quit() 并重建。
- 替代思路(进阶):对极致性能要求场景,可考虑无头浏览器池(如 Playwright 的 browser.new_context())或 HTTP 客户端(Requests + beautifulsoup)直取静态内容,绕过浏览器渲染层。
综上,Selenium 的内存问题本质是架构约束而非 bug——它设计初衷并非高并发标签页调度。接受 quit()/new 的轻量重启成本,是平衡稳定性与资源消耗的最优解。 将“单实例长连接”思维切换为“短生命周期批处理”,即可从容应对 600+ 页面规模的自动化采集任务。