Selenium执行driver.quit()后仍CPU占用100%问题排查与优化
我使用Selenium搭配Chromedriver爬取batdongsan.com.vn网站数据,需程序连续运行6小时以上。初期driver.quit()可正常关闭所有标签页,但运行约5-6小时后CPU占用率升至100%,出现10-15个无法关闭的Chrome标签页。我同时在本地Jupyter Notebook和Colab运行代码,前者5小时后过载,后者12小时后运行缓慢。代码如下:
# setup chrome options chrome_options = webdriver.ChromeOptions() chrome_options.add_argument('--headless') # ensure GUI is off chrome_options.add_argument('--no-sandbox') chrome_options.add_argument('--disable-dev-shm-usage') chrome_options.add_argument("--nogpu") chrome_options.add_argument("--disable-gpu") chrome_options.add_argument("--window-size=1280,1280") chrome_options.add_argument("--no-sandbox") chrome_options.add_argument("--enable-javascript") chrome_options.add_experimental_option("excludeSwitches", ["enable-automation"]) chrome_options.add_experimental_option('useAutomationExtension', False) chrome_options.add_argument('--disable-blink-features=AutomationControlled') while page < len(listed): print(page) ua = UserAgent() userAgent = ua.random # set path to chromedriver as per your configuration chromedriver_autoinstaller.install() # set the target URL url = 'https://batdongsan.com.vn' + listed[page] # set up the webdriver driver = webdriver.Chrome(options=chrome_options) driver.execute_script("Object.defineProperty(navigator, 'webdriver', {get: () => undefined})") driver.execute_cdp_cmd('Network.setUserAgentOverride', {"userAgent": userAgent}) driver.get(url) # Wait for the page to load driver.implicitly_wait(10) # Get the page source html_data = driver.page_source # Parse the HTML data using BeautifulSoup soup = BeautifulSoup(html_data, 'html.parser') # Close the web driver driver.quit() page += 1
请问是我的代码存在问题,还是Selenium本身占用大量CPU?有没有方法降低Selenium的CPU占用率,或确保每次会话后所有标签页都被关闭?
你的代码存在多处可优化的问题,这些问题是导致CPU过载、进程残留的主要原因,结合Selenium本身的特性,可通过以下方式解决:
一、修复代码中的核心问题
1. 移除重复的Chromedriver安装
每次循环执行chromedriver_autoinstaller.install()会反复检查版本、写入文件,既浪费资源也可能引发进程锁定,只需在循环外执行一次即可:
chromedriver_autoinstaller.install() # 移到循环前,仅执行一次 ua = UserAgent() # UserAgent实例也无需每次循环创建 while page < len(listed): # 后续循环逻辑
2. 用异常处理确保driver必关闭
如果页面加载失败、解析出错,driver.quit()可能不会执行,导致Chrome进程残留。用try...finally块强制关闭driver:
while page < len(listed): print(page) userAgent = ua.random url = 'https://batdongsan.com.vn' + listed[page] driver = None try: driver = webdriver.Chrome(options=chrome_options) driver.execute_script("Object.defineProperty(navigator, 'webdriver', {get: () => undefined})") driver.execute_cdp_cmd('Network.setUserAgentOverride', {"userAgent": userAgent}) driver.get(url) driver.implicitly_wait(10) html_data = driver.page_source soup = BeautifulSoup(html_data, 'html.parser') # 此处添加数据处理逻辑 except Exception as e: print(f"处理页面{page}出错: {str(e)}") finally: if driver is not None: driver.quit() # 无论是否出错,都关闭driver page += 1
3. 优化Chrome启动参数
移除重复、冗余参数,添加更节省资源的配置:
chrome_options = webdriver.ChromeOptions() chrome_options.add_argument('--headless=new') # 新版headless模式,资源占用更低 chrome_options.add_argument('--no-sandbox') chrome_options.add_argument('--disable-dev-shm-usage') chrome_options.add_argument("--disable-gpu") chrome_options.add_argument("--window-size=800,600") # 缩小窗口,减少渲染开销 chrome_options.add_experimental_option("excludeSwitches", ["enable-automation"]) chrome_options.add_experimental_option('useAutomationExtension', False) chrome_options.add_argument('--disable-blink-features=AutomationControlled') # 添加资源优化参数 chrome_options.add_argument('--disable-images') # 无需图片时禁用加载 chrome_options.add_argument('--disable-plugins') chrome_options.add_argument('--disable-extensions') chrome_options.add_argument('--disable-background-networking')
二、降低CPU占用的进阶措施
1. 复用单个driver实例
每次循环创建新driver会带来大量进程开销,可复用一个driver,通过切换标签页完成爬取:
chromedriver_autoinstaller.install() ua = UserAgent() driver = webdriver.Chrome(options=chrome_options) driver.execute_script("Object.defineProperty(navigator, 'webdriver', {get: () => undefined})") try: while page < len(listed): print(page) userAgent = ua.random driver.execute_cdp_cmd('Network.setUserAgentOverride', {"userAgent": userAgent}) url = 'https://batdongsan.com.vn' + listed[page] # 打开新标签页并切换 driver.execute_script(f"window.open('{url}');") driver.switch_to.window(driver.window_handles[-1]) driver.implicitly_wait(10) html_data = driver.page_source soup = BeautifulSoup(html_data, 'html.parser') # 数据处理逻辑 # 关闭当前标签页并切回主窗口 driver.close() driver.switch_to.window(driver.window_handles[0]) page += 1 finally: driver.quit() # 最后统一关闭driver
2. 添加请求间隔
高频请求会同时消耗本地和服务器资源,也容易触发反爬,在循环末尾添加间隔:
import time # 循环末尾添加 time.sleep(1) # 可根据实际情况调整间隔时长
3. 优先使用非浏览器爬取
如果目标页面无需执行JavaScript,直接用requests+BeautifulSoup爬取,完全避免浏览器的资源开销,仅在必须处理JS渲染时使用Selenium。
三、强制清理残留进程
如果仍有Chrome进程残留,可在driver.quit()后手动清理(仅本地环境适用,Colab不建议):
import psutil def kill_chrome_processes(): for proc in psutil.process_iter(['name']): try: if proc.name() in ['chrome.exe', 'chromedriver.exe', 'chrome']: proc.kill() except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess): pass # 在finally块中调用 finally: if driver is not None: driver.quit() kill_chrome_processes()
内容的提问来源于stack exchange,提问作者Huy Nguyễn

