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

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

一、文件上传

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

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

python 复制代码
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

driver = 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 触发文件选择。对于这种情况:

python 复制代码
from selenium import webdriver
from selenium.webdriver.common.by import By

driver = 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. 多文件上传

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

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

二、文件下载

1. 配置浏览器下载选项

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

python 复制代码
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. 等待下载完成

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

python 复制代码
import os
import time

def wait_for_download_complete(download_dir, timeout=30, check_interval=1):
    """
    等待下载目录中的 .crdownload 文件消失(Chrome)
    """
    end_time = time.time() + timeout
    while time.time() < end_time:
        # 检查是否有未完成的下载文件(Chrome使用.crdownload扩展名)
        if not any(fname.endswith('.crdownload') for fname in os.listdir(download_dir)):
            return True
        time.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. 获取下载的文件信息

python 复制代码
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:
                continue
            files.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 浏览器
python 复制代码
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 浏览器
python 复制代码
from selenium.webdriver.firefox.options import Options
from selenium.webdriver.firefox.service import Service

firefox_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 浏览器
python 复制代码
from selenium.webdriver.edge.options import Options

edge_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)

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

python 复制代码
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 False
        return True
    
    wait.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. 下载对话框弹出

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

python 复制代码
prefs = {
    "download.default_directory": download_dir,
    "download.prompt_for_download": False,  # 关键设置
    # ...
}

2. 下载文件名为乱码

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

python 复制代码
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. 处理大文件下载

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

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

4. 清理下载目录

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

python 复制代码
import shutil

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

五、最佳实践

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

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

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

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

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

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

相关推荐
Meta Luo19 小时前
页面改版后自动化用例大量失败,应该怎么维护?
运维·功能测试·测试工具·自动化
释槐鸟~1 天前
还不知道RIDE工具怎么装吗
测试工具·自动化
有技巧搬砖2 天前
为什么锂电池组的电池老化测试很重要?
测试工具·锂电池·电池老化
蒲公英内测分发2 天前
智能手表卖出去后,包装、说明书和官网里的 App 下载入口怎么统一?
前端·人工智能·测试工具·智能家居·智能硬件·智能手表
蒲公英内测分发2 天前
智能手环出海测试,海外合作方分散在不同国家,Android 测试包怎么持续分发和更新?
android·前端·人工智能·测试工具·智能手表
无语的小歪歪2 天前
ATF 智测 1.0
python·测试工具·集成测试
SHENGWEI胜为3 天前
交换机端口显示正常,终端却获取不到 IP 地址?从 DHCP 流程定位故障
服务器·网络·测试工具·缓存·通信工程
xie881018023 天前
长表格跨页重复表头:排版上的做法
测试工具
老孟说禅3 天前
测试工具示波器的使用
测试工具
步行cgn4 天前
为什么使用接口测试工具?
测试工具