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. 错误处理:添加适当的异常处理,处理下载失败或超时的情况。

相关推荐
晨曦54321010 小时前
Selenium 实战项目:电子商务网站自动化测试
selenium·测试工具
币圈小菜鸟12 小时前
Selenium 自动化测试实战:绕过登录直接获取 Cookie
linux·python·selenium·测试工具·ubuntu·自动化
AIZHINAN12 小时前
Pytest 插件介绍和开发
测试工具·pytest·插件开发
一百天成为python专家13 小时前
python爬虫之selenium库进阶(小白五分钟从入门到精通)
开发语言·数据库·pytorch·爬虫·python·深度学习·selenium
q5673152315 小时前
解决爬虫IP限制:Selenium隧道代理完整解决方案
爬虫·tcp/ip·selenium
ayaya_mana1 天前
oha:一款轻量级HTTP负载测试工具
网络协议·测试工具·http
只看不学2 天前
selenium自动下载更新浏览器对应的webdriver
selenium·测试工具
BatyTao2 天前
Selenium自动化测试快速入门指南
python·selenium·测试工具