使用Selenium爬虫时遇MemoryError与RuntimeError问题求助
解决Selenium爬虫的MemoryError和RuntimeError: can't start new thread问题
我帮你分析下这个问题,你遇到的MemoryError和RuntimeError: can't start new thread,核心原因是Selenium的ChromeDriver长时间运行后,浏览器进程的内存持续累积、线程资源被耗尽——哪怕你清空了Python里的列表,浏览器本身的缓存、DOM元素、后台线程没被正确释放,还是会撑爆资源。结合你的代码,给你几个落地的解决方案:
一、给Chrome加启动参数,大幅降低内存占用
Chrome默认会加载很多不必要的功能(比如图片、扩展、缓存),这些都会占用大量内存。启动时添加以下参数,能砍掉大部分冗余消耗:
from selenium import webdriver from selenium.webdriver.chrome.options import Options chrome_options = Options() # 禁用图片加载(如果不需要爬取图片的话) chrome_options.add_argument('--blink-settings=imagesEnabled=false') # 禁用缓存,避免累积页面缓存 chrome_options.add_argument('--disable-cache') # 禁用浏览器扩展 chrome_options.add_argument('--disable-extensions') # 启用无头模式(不需要可视化界面时用,内存占用更低) chrome_options.add_argument('--headless=new') # 禁用GPU加速,减少渲染资源消耗 chrome_options.add_argument('--disable-gpu') # Windows下可选:禁用沙箱,避免额外线程开销 chrome_options.add_argument('--no-sandbox') # 用配置好的参数启动driver driver = webdriver.Chrome(options=chrome_options)
二、定期重启浏览器,彻底释放资源
哪怕加了参数,Chrome运行几十页后还是会有内存泄漏。最直接的办法是每处理一定数量的店铺/页面后,关闭当前浏览器进程,重新启动并登录,彻底清空资源:
store_count = 0 login_url = 'https://login.aliexpress.com/' for index, row in df.iterrows(): store_count += 1 # 每处理10个店铺就重启一次浏览器(数量可以根据自己的情况调整) if store_count % 10 == 0: driver.quit() # 重新初始化driver并完成登录流程 driver = webdriver.Chrome(options=chrome_options) driver.implicitly_wait(30) driver.get(login_url) time.sleep(3) driver.switch_to.frame('alibaba-login-box') driver.find_element_by_id('fm-login-id').send_keys('你的账号') driver.find_element_by_id('fm-login-password').send_keys('你的密码') driver.find_element_by_id('fm-login-submit').click() time.sleep(3) driver.switch_to.default_content() # 后续的店铺页面爬取代码...
三、换掉driver.back(),改用新标签页处理商品页
你现在用driver.back()回到列表页,这个操作会保留之前商品页的DOM和状态,时间久了会积累大量无用数据。改用新标签页打开商品页,处理完就关闭标签页,能避免这个问题:
# 遍历商品链接时,用新标签页打开 for link in links: # 执行JS打开新标签页 driver.execute_script(f"window.open('{link}');") # 切换到新打开的标签页 driver.switch_to.window(driver.window_handles[-1]) time.sleep(2) soup1 = BeautifulSoup(driver.page_source, 'html.parser') # 处理商品详情数据... # 关闭当前标签页 driver.close() # 切回列表页的标签页 driver.switch_to.window(driver.window_handles[0])
四、优化数据存储逻辑,减少内存中的数据堆积
你现在是攒够500条数据再写入CSV,这会让price、prod_name这些列表在内存里越来越大。改成每处理完一个商品就直接写入CSV,彻底避免内存堆积:
# 提前打开CSV文件,保持写入状态 with open('output.csv', 'a', newline='') as f: writer = csv.writer(f) # 写表头(如果文件是新的) # writer.writerow(['商品名称', '价格', '链接', '规格']) for index, row in df.iterrows(): # 处理店铺列表页... links = [link.get_attribute('href') for link in driver.find_elements_by_xpath("//div[@id='node-gallery']/div[5]/div/div/ul/li/div[2]/h3/a")] for link in links: # 打开新标签页处理商品... # 处理完后组装当前商品的数据 current_prod_data = (prod_name_t, div_b_text + 'Ł', prod_name_l + 'Ł', item_specs_replace) # 直接写入CSV writer.writerow(current_prod_data)
五、排查线程泄漏的补充建议
RuntimeError: can't start new thread通常是因为进程的线程数达到了系统上限。除了上面的重启浏览器方案,你还可以:
- 打开任务管理器(Windows)或
htop(Linux),查看Chrome进程的线程数,如果持续增长,说明确实有线程泄漏,重启是最有效的解决办法。 - 避免在代码中手动创建额外线程,Selenium本身已经在后台管理大量线程,额外线程会加速耗尽资源。
六、用工具定位内存泄漏点(可选)
如果还是不确定哪里在耗内存,可以用tracemalloc工具分析内存使用情况,找出最耗内存的代码段:
import tracemalloc # 启动内存跟踪 tracemalloc.start() # 你的爬虫代码... # 生成内存快照并打印Top10内存消耗点 snapshot = tracemalloc.take_snapshot() top_stats = snapshot.statistics('lineno') print("Top 10内存消耗点:") for stat in top_stats[:10]: print(stat)
按照上面的方案调整后,你的爬虫应该能稳定运行完所有网站了。
内容的提问来源于stack exchange,提问作者ViktorovicsL
相关产品推荐
相关产品推荐

