使用Selenium下载文件时如何获取实际保存的正确文件名?
你遇到的文件名与a标签文本不一致的问题,本质是服务端为了避免重名、做缓存标识等需求,在下载响应时动态追加了时间戳后缀,该后缀不会提前暴露在前端a标签的属性或文本中,因此需要从下载链路的下游环节获取真实文件名,以下是三种可行方案:
方案1:拦截下载请求的响应头获取
- 核心逻辑:下载请求的响应头
Content-Disposition字段会携带服务端指定的最终文件名,直接读取该字段即可拿到准确名称。 - 实现依赖:需要用
selenium-wire替换原生Selenium实现网络请求拦截,示例代码如下:
from seleniumwire import webdriver driver = webdriver.Chrome() driver.get("你的目标页面地址") link1 = driver.find_element_by_xpath("//a[@id='rfq-display-attachment-0']") # 提前获取下载链接用于后续请求匹配 target_href = link1.get_attribute('href') link1.click() # 遍历拦截到的请求匹配对应下载请求 for request in driver.requests: if request.url == target_href and request.response: # 解析Content-Disposition字段 content_disposition = request.response.headers.get('Content-Disposition', '') if 'filename=' in content_disposition: # 提取文件名并去掉前后引号 real_filename = content_disposition.split('filename=')[1].strip('"') print(real_filename) break
- 注意事项:如果下载链接有302跳转,可以匹配跳转后的最终请求地址即可。
方案2:监听下载目录的文件变化
- 核心逻辑:浏览器下载文件时会先生成后缀为
.crdownload(Chrome)/.part(Firefox)的临时文件,下载完成后才会重命名为最终文件名,只需监控下载目录等待文件落地即可拿到真实名称,该方案兼容性最强,不需要修改请求逻辑。 - 示例代码:
import os import time # 替换为你的浏览器默认下载目录路径 DOWNLOAD_DIR = "/Users/xxx/Downloads" # 点击下载前记录目录现有文件列表 before_download = set(os.listdir(DOWNLOAD_DIR)) link1.click() # 等待下载完成,超时时间30秒可自行调整 timeout = 30 start_time = time.time() real_filename = None while time.time() - start_time < timeout: after_download = set(os.listdir(DOWNLOAD_DIR)) new_files = after_download - before_download # 过滤未完成的临时文件 valid_files = [f for f in new_files if not f.endswith('.crdownload') and not f.endswith('.part')] if valid_files: # 如果同时有多个文件下载,可以增加前缀匹配逻辑过滤 real_filename = [f for f in valid_files if f.startswith('BEHR SDS')][0] break time.sleep(1) print(real_filename)
方案3:调用Chrome DevTools Protocol(CDP)获取下载信息
- 核心逻辑:如果你使用Chrome/Edge内核浏览器,可以直接调用浏览器内置的CDP接口监听下载事件,能直接拿到浏览器确认的最终下载文件名,不需要解析请求也不需要扫描目录。
- 示例代码:
from selenium import webdriver import time driver = webdriver.Chrome() # 启用Downloads域事件监听 driver.execute_cdp_cmd('Page.enable', {}) driver.execute_cdp_cmd('Downloads.enable', {}) real_filename = None # 绑定下载事件回调,拿到文件名 def on_download_begin(params): global real_filename real_filename = params['suggestedFilename'] driver.add_cdp_listener('Downloads.downloadWillBegin', on_download_begin) # 点击触发下载 link1.click() # 等待事件触发 while not real_filename: time.sleep(0.5) print(real_filename)
内容的提问来源于stack exchange,提问作者Rikky Bhai
相关产品推荐
相关产品推荐

