Python Selenium批量下载文件后driver.quit()失效挂起问题
问题根因
驱动无法退出挂死的核心原因有两个:
- 下载触发逻辑是异步的:Selenium执行点击下载链接的动作后,Firefox会在后台独立进程中完成文件传输和写入,循环结束时大部分文件并未下载完成。此时调用
driver.quit()会等待所有浏览器关联进程(包括正在执行IO的下载进程)退出才会返回,直接进入无限等待状态。 - 下载配置不全:现有配置仅放行
application/force-download类型的自动下载,未覆盖目标站点返回的实际文件MIME类型,可能触发浏览器后台隐藏的下载确认弹窗,阻塞进程退出。 - 配置写法错误:原代码将
service_log_path作为Firefox偏好设置传入,该参数实际是WebDriver初始化参数,传入后不生效,可能导致日志进程异常挂起。
修复方案
- 补全Firefox下载相关配置,将站点常见的压缩包、数据文件MIME类型加入自动保存列表,避免隐式弹窗阻塞。
- 新增下载完成检测逻辑:轮询下载目录,通过Firefox下载临时文件(
.part后缀)是否全部消失判定下载状态,确认所有文件写入完成后再执行退出操作。 - 增加进程终止兜底逻辑,退出时先调用常规
quit()方法,再强制停止geckodriver服务,避免残留进程挂起。 - 下载路径必须使用绝对路径,避免相对路径导致的文件检测、下载位置异常。
修正后可正常退出的完整代码如下:
import os import time import requests from bs4 import BeautifulSoup as bs from selenium import webdriver from selenium.webdriver.firefox.options import Options from selenium.webdriver.common.by import By #step-1: 获取文件列表 # 注意:verify=False仅用于测试,正式环境建议配置站点证书信任 data_url_page = requests.get("https://mft.rrc.texas.gov/link/0e33071d-9891-4009-970c-5aa26da5e31a", verify=False) files_list = [] soup = bs(data_url_page.content, "lxml") for table_div in soup.find_all('div', class_='ui-datatable-tablewrapper'): files_td = table_div.find_all('td', class_='NameColumn') for file_name in files_td: if file_name: files_list.append(file_name.get_text().strip()) # 替换为本地下载目录的绝对路径 DOWNLOAD_DIR = "/absolute/path/to/your/download/dir/" os.makedirs(DOWNLOAD_DIR, exist_ok=True) def wait_all_download_complete(timeout=1800): """等待所有文件下载完成,默认超时30分钟兜底""" start_time = time.time() while time.time() - start_time < timeout: # Firefox下载中的文件会以.part为临时后缀 downloading_files = [f for f in os.listdir(DOWNLOAD_DIR) if f.endswith('.part')] if not downloading_files: # 二次校验:等待2秒后确认无临时文件,避免小文件写入尾期误判 time.sleep(2) recheck = [f for f in os.listdir(DOWNLOAD_DIR) if f.endswith('.part')] if not recheck: return True time.sleep(3) return False #step-2: 批量下载文件 def http_file_downloader(data_url_files, files_list): options = Options() options.add_argument("--headless") options.set_preference("browser.download.folderList", 2) options.set_preference("browser.download.manager.showWhenStarting", False) options.set_preference("browser.download.dir", DOWNLOAD_DIR) # 补全站点常见文件MIME类型,全部自动保存不弹窗 auto_save_mime = """ application/zip,application/x-zip-compressed,application/octet-stream, application/x-gzip,text/csv,application/pdf,application/force-download """ options.set_preference("browser.helperApps.neverAsk.saveToDisk", auto_save_mime.replace("\n","").strip()) driver = webdriver.Firefox(options=options) try: driver.get(data_url_files) # 等待页面列表加载完成 time.sleep(5) for file_name in files_list: xpath = f'//a[text()="{file_name}"]' elem = driver.find_element(by=By.XPATH, value=xpath) elem.click() # 点击间隔避免请求过密被站点拦截 time.sleep(0.5) # 等待所有下载完成后再退出 wait_all_download_complete() finally: # 双层退出逻辑兜底,避免进程挂起 try: driver.quit() except Exception: pass # 强制停止geckodriver服务,彻底释放所有关联进程 driver.service.stop() # 启动下载 http_file_downloader("https://mft.rrc.texas.gov/link/0e33071d-9891-4009-970c-5aa26da5e31a", files_list)
内容的提问来源于stack exchange,提问作者ravi n
相关产品推荐
相关产品推荐

