当前位置: 首页 > news >正文

Selenium 4 文件上传和下载操作指南

        Selenium 文件上传和下载 | 菜鸟教程这篇文章讲了Selenium4 文件上传和下载的基本知识点,我建议你先看完上面那篇文章学习基础,然后再学习下面的。

一、文件上传

1. 基本文件上传(使用 send_keys)

对于标准的 <input type="file"> 元素,最简单的方法是直接使用 send_keys() 发送文件路径:

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as ECdriver = webdriver.Chrome()
driver.get("https://example.com/upload")# 找到文件上传输入框
file_input = driver.find_element(By.CSS_SELECTOR, "input[type='file']")# 发送文件绝对路径
file_input.send_keys("/path/to/your/file.txt")# 点击上传按钮(如果有)
upload_button = driver.find_element(By.ID, "upload-button")
upload_button.click()

2. 处理隐藏的文件输入框

有些网站使用自定义样式隐藏了原生的文件输入框,然后通过 JavaScript 触发文件选择。对于这种情况:

from selenium import webdriver
from selenium.webdriver.common.by import Bydriver = webdriver.Chrome()
driver.get("https://example.com/upload")# 找到隐藏的文件输入框(可能需要查看页面源代码)
hidden_file_input = driver.find_element(By.ID, "hidden-file-input")# 使用JavaScript使元素可见(如果需要)
driver.execute_script("arguments[0].style.display = 'block';", hidden_file_input)# 发送文件路径
hidden_file_input.send_keys("/path/to/your/file.txt")

3. 使用 AutoIT 或 Sikuli 处理系统对话框(不推荐)

对于某些无法直接通过 Selenium 操作的系统级文件选择对话框,可以考虑使用 AutoIT 或 Sikuli,但这些方法不够稳定且跨平台性差,应尽量避免。

4. 多文件上传

如果需要上传多个文件,可以发送多个文件路径,用换行符分隔:

# 上传多个文件
file_input.send_keys("/path/to/file1.txt\n/path/to/file2.txt\n/path/to/file3.txt")

二、文件下载

1. 配置浏览器下载选项

在 Selenium 4 中,我们可以通过浏览器选项来配置下载行为:

from selenium import webdriver
from selenium.webdriver.chrome.options import Options# 设置下载选项
chrome_options = Options()# 设置下载路径
download_dir = "/path/to/download/directory"# Chrome 浏览器配置
prefs = {"download.default_directory": download_dir,"download.prompt_for_download": False,  # 禁止弹出下载对话框"download.directory_upgrade": True,"safebrowsing.enabled": True  # 禁用安全浏览,以避免下载延迟
}chrome_options.add_experimental_option("prefs", prefs)# 创建浏览器实例
driver = webdriver.Chrome(options=chrome_options)

2. 等待下载完成

下载文件后,我们需要等待下载完成:

import os
import timedef wait_for_download_complete(download_dir, timeout=30, check_interval=1):"""等待下载目录中的 .crdownload 文件消失(Chrome)"""end_time = time.time() + timeoutwhile time.time() < end_time:# 检查是否有未完成的下载文件(Chrome使用.crdownload扩展名)if not any(fname.endswith('.crdownload') for fname in os.listdir(download_dir)):return Truetime.sleep(check_interval)return False# 点击下载链接
download_link = driver.find_element(By.ID, "download-link")
download_link.click()# 等待下载完成
if wait_for_download_complete(download_dir):print("下载完成")
else:print("下载超时")

3. 获取下载的文件信息

def get_downloaded_file_info(download_dir, pattern=None):"""获取下载目录中的文件信息"""files = []for filename in os.listdir(download_dir):filepath = os.path.join(download_dir, filename)if os.path.isfile(filepath):# 如果指定了模式,只返回匹配的文件if pattern and not pattern in filename:continuefiles.append({"name": filename,"path": filepath,"size": os.path.getsize(filepath),"modified": os.path.getmtime(filepath)})# 按修改时间排序,最新的在前files.sort(key=lambda x: x["modified"], reverse=True)return files# 获取所有下载的文件
downloaded_files = get_downloaded_file_info(download_dir)# 获取最新下载的文件
if downloaded_files:latest_file = downloaded_files[0]print(f"最新下载的文件: {latest_file['name']}, 大小: {latest_file['size']} 字节")

4. 处理不同浏览器的下载

不同浏览器需要不同的配置:

Chrome 浏览器
chrome_options = Options()
prefs = {"download.default_directory": download_dir,"download.prompt_for_download": False,"download.directory_upgrade": True,"safebrowsing.enabled": True
}
chrome_options.add_experimental_option("prefs", prefs)
driver = webdriver.Chrome(options=chrome_options)
Firefox 浏览器
from selenium.webdriver.firefox.options import Options
from selenium.webdriver.firefox.service import Servicefirefox_options = Options()
firefox_options.set_preference("browser.download.folderList", 2)  # 0=桌面, 1=默认, 2=自定义
firefox_options.set_preference("browser.download.dir", download_dir)
firefox_options.set_preference("browser.download.useDownloadDir", True)
firefox_options.set_preference("browser.helperApps.neverAsk.saveToDisk", "application/octet-stream,application/pdf,text/csv")
firefox_options.set_preference("pdfjs.disabled", True)  # 禁用内置PDF查看器driver = webdriver.Firefox(options=firefox_options)
Edge 浏览器
from selenium.webdriver.edge.options import Optionsedge_options = Options()
prefs = {"download.default_directory": download_dir,"download.prompt_for_download": False,"download.directory_upgrade": True,"safebrowsing.enabled": True
}
edge_options.add_experimental_option("prefs", prefs)
driver = webdriver.Edge(options=edge_options)

三、实战示例:完整的文件上传和下载流程

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.chrome.options import Options
import os
import time# 设置下载目录
download_dir = os.path.abspath("./downloads")
if not os.path.exists(download_dir):os.makedirs(download_dir)# 配置浏览器选项
chrome_options = Options()
prefs = {"download.default_directory": download_dir,"download.prompt_for_download": False,"download.directory_upgrade": True,"safebrowsing.enabled": True
}
chrome_options.add_experimental_option("prefs", prefs)# 创建浏览器实例
driver = webdriver.Chrome(options=chrome_options)
wait = WebDriverWait(driver, 10)try:# 1. 上传文件driver.get("https://example.com/upload")# 找到并上传文件file_input = wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, "input[type='file']")))file_input.send_keys(os.path.abspath("./test_upload.txt"))# 点击上传按钮upload_button = driver.find_element(By.ID, "upload-btn")upload_button.click()# 等待上传完成wait.until(EC.text_to_be_present_in_element((By.ID, "status"), "上传成功"))# 2. 下载文件download_link = wait.until(EC.element_to_be_clickable((By.ID, "download-link")))download_link.click()# 等待下载完成def is_download_complete():# 检查是否有.crdownload临时文件for fname in os.listdir(download_dir):if fname.endswith('.crdownload'):return Falsereturn Truewait.until(lambda driver: is_download_complete())# 获取下载的文件downloaded_files = [f for f in os.listdir(download_dir) if os.path.isfile(os.path.join(download_dir, f))]if downloaded_files:latest_file = max(downloaded_files, key=lambda f: os.path.getmtime(os.path.join(download_dir, f)))print(f"成功下载文件: {latest_file}")# 验证文件内容(如果需要)file_path = os.path.join(download_dir, latest_file)with open(file_path, 'r') as f:content = f.read()print(f"文件内容: {content[:100]}...")  # 只打印前100个字符finally:driver.quit()

四、常见问题与解决方案

1. 下载对话框弹出

如果仍然看到下载对话框,确保正确设置了浏览器偏好设置:

prefs = {"download.default_directory": download_dir,"download.prompt_for_download": False,  # 关键设置# ...
}

2. 下载文件名为乱码

某些情况下,下载的文件名可能包含乱码。可以尝试重命名文件:

import urllib.parse# 从Content-Disposition头获取文件名(如果可用)
content_disposition = driver.execute_script("return arguments[0].getAttribute('download')", download_link
)
if content_disposition:filename = urllib.parse.unquote(content_disposition)# 重命名文件latest_file = get_latest_downloaded_file(download_dir)os.rename(latest_file, os.path.join(download_dir, filename))

3. 处理大文件下载

对于大文件下载,可能需要增加超时时间:

def wait_for_download_complete(download_dir, timeout=300):  # 5分钟超时# ... 实现同上

4. 清理下载目录

在测试开始前清理下载目录,避免旧文件干扰:

import shutil# 清理下载目录
if os.path.exists(download_dir):shutil.rmtree(download_dir)
os.makedirs(download_dir)

五、最佳实践

  1. 使用绝对路径:始终使用文件的绝对路径,避免相对路径可能带来的问题。

  2. 合理设置超时:根据文件大小和网络状况设置合理的超时时间。

  3. 验证下载内容:不仅检查文件是否存在,还应验证文件内容和大小。

  4. 清理测试环境:测试开始前清理下载目录,确保测试环境干净。

  5. 跨浏览器考虑:不同浏览器需要不同的配置,确保你的代码能处理这些差异。

  6. 错误处理:添加适当的异常处理,处理下载失败或超时的情况。

http://www.dtcms.com/a/361640.html

相关文章:

  • kubernetes应用的包管理Helm工具
  • MySql blob转string
  • 15693协议ICODE SLI 系列标签应用场景说明及读、写、密钥认证操作Qt c++源码,支持统信、麒麟等国产Linux系统
  • 【Pycharm】Pychram软件工具栏Git和VCS切换
  • 【数据可视化-102】苏州大学招生计划全解析:数据可视化的五大维度
  • 从零开始实现Shell | Linux进程调度实战
  • AI时代SEO关键词实战解析
  • Scala协变、逆变、上界/下界、隐式参数、隐式转换
  • daily notes[7]
  • Windows系统下如何配置和使用jfrog.exe
  • Ansible变量的定义与使用
  • docker 网络配置
  • MJ Prompt Tool-好用的Midjourney提示词工具
  • uniApp 混合开发全指南:原生与跨端的协同方案
  • 机器学习通关秘籍|Day 05:过拟合和欠拟合、正则化、岭回归、拉索回归、逻辑回归、Kmeans聚类
  • ChatGLM-6B全流程部署:环境搭建→模型加载→API调用(附避坑指南)
  • 【项目思维】这是一份嵌入式软件开发的大纲(简化版)
  • Go 面试题: new 和 make 是什么,差异在哪?
  • window显示驱动开发—监视筛选器驱动程序
  • 如何安装CUDA????
  • 在 Qt 中加载 .qm 翻译文件
  • 基本问题解决--舵机
  • 选择图片转base64格式组件简单封装-Base64ImageInpu
  • nestjs 发起请求 axios
  • Onion-LO(已开源)——LIDAR里程计的统一框架
  • IO进程线程;标准io;文件IO;0901
  • PyTorch 实战(3)—— PyTorch vs. TensorFlow:深度学习框架的王者之争
  • 「日拱一码」075 机器学习——密度泛函理论DFT
  • 在 Unity 中调用腾讯云机器翻译
  • 命名空间级别应用 Pod 安全标准