Selenium上传文件方法总结

Selenium上传文件方法总结

Web上本地上传图片,弹出的框Selenium是无法识别的,也就是说,selenium本身没有直接的方法去实现上传本地文件,这里总结了两种上传文件的方式。

一、利用Robot类处理文件上传。

其大致流程可以为:

1、 利用selenium点击web上本地文件的上传按钮;

2、 在弹出的弹框中,文件路径输入框默认的是光标的聚焦,将文件在磁盘上的路径通过拷贝和黏贴的方法写上去。

3、 通过按下回车,默认触发弹框的确定按钮,完成文件上传的功能。

这里以百度首页的利用图片搜索为例:

  打开百度首页,搜索按钮左侧有一个照相机的图标,点击可以选择图片搜索,我们通过本地上传图片的过程来模拟文件自动化上传操作。准备条件,在百度图片搜索一个图片,保存到桌面,例如找到一个关于selenium的图片,然后保存在桌面,名称为selenium.jpg。

相关实现代码如下:

package first;

import java.awt.Robot;

import java.awt.Toolkit;

import java.awt.datatransfer.StringSelection;

import java.awt.event.KeyEvent;

import java.util.concurrent.TimeUnit;

import org.openqa.selenium.By;

import org.openqa.selenium.WebDriver;

import org.openqa.selenium.firefox.FirefoxDriver;

public class shangchuang {

public static void main(String[] args)throws Exception {

    WebDriver driver=new FirefoxDriver();

    driver.manage().window().maximize();

    driver.manage().timeouts().implicitlyWait(4, TimeUnit.SECONDS);

   

    driver.get(“https://www.baidu.com”);

    //指定图片路径

    StringSelection selection=new StringSelection(“C:\\Users\\你的用户名\\Desktop\\selenium.jpg”);

    //把图片路径复制到剪切板

    Toolkit.getDefaultToolkit().getSystemClipboard().setContents(selection, null);

    System.out.println(“selection”+selection);

    //点击照相机这个工具

    driver.findElement(By.xpath(“//*/span[@class=’soutu-btn’]”)).click();

    //点击本地上传图片

    driver.findElement(By.xpath(“//*/div[@class=’upload-wrap’]”)).click();

  

    //新建一个Robot类的对象

    Robot robot=new Robot();

    Thread.sleep(1000);

    //按下Ctrl+V

    robot.keyPress(KeyEvent.VK_CONTROL);

    robot.keyPress(KeyEvent.VK_V);

    //释放Ctrl+V

    robot.keyRelease(KeyEvent.VK_CONTROL);

    robot.keyRelease(KeyEvent.VK_V);

    Thread.sleep(2000);

    //点击回车

    robot.keyPress(KeyEvent.VK_ENTER);

    robot.keyRelease(KeyEvent.VK_ENTER);

}

}

二、利用AutoIt上传文件

以上是第一种方的实现,第二种方式是利用AutoIt这个工具。这是一个能支持桌面GUI自动化的工具,它支持脚本语言编写。在Selenium脚本中如果需要AutoIt来协助这个文件上传功能,大概步骤是这样的:

1. Selenium点击web产品上的文件上传按钮,弹窗上传框。

2.执行AutoIt实现准备好的脚本文件,这个脚本文件写了关于上传什么文件的一个.exe文件。

在一切测试工作之前,我们先下载和安装AutoIt。

1)打开AutoIt的官网下载地址

https://www.autoitscript.com/site/autoit/downloads/

2)点击下载zip,当然也可以下载Editor。

 

解压得到的效果如图:

 

3)点击SciTe文件夹,我们打开脚本编辑器。双击SciTE.exe

4)打开百度图片上传窗口,同时打开AutoIt 脚本编辑器和元素定位器。拖动元素定位器上那个靶点形状按钮到文件上传弹窗,能够捕获到一些元素信息。

 

5)在AutoIt脚本编辑器里输入如下脚本,绿色部分为解释的,不需要写。

6)编译成一个.exe文件

先保存到本地,例如默认路径保存,名称为UploadFile.au3,然后在AutoIt脚本编辑器中点击Tools菜单,选择compile,会在同路径下生成一个UploadFile.exe的文件,待会在Selenium脚本要使用。

 

7)Selenium脚本执行UploadFile.exe文件,观察文件是否上传。

package first;

import java.util.concurrent.TimeUnit;

import org.openqa.selenium.By;

import org.openqa.selenium.WebDriver;

import org.openqa.selenium.firefox.FirefoxDriver;

public class AutoIt {

public static void main(String[] args) throws Exception{

    WebDriver driver=new FirefoxDriver();

    driver.manage().window().maximize();

    driver.manage().timeouts().implicitlyWait(4, TimeUnit.SECONDS);

   

    driver.get(“http://www.baidu.com”);

    //点击照相机这个工具

    driver.findElement(By.xpath(“//*/span[@class=’soutu-btn’]”)).click();

    //点击本地上传图片 

    driver.findElement(By.xpath(“//*/div[@class=’upload-wrap’]”)).click();

    // 执行桌面的AutoIt封装的脚本

    Runtime.getRuntime().exec(“C:\\Users\\你的用户名\\Desktop\\UploadFile.exe”);

}

}

我用的是火狐62,最终的效果如图所示:

 

三、把文件信息上传给选择按钮(针对input标签)。

以下是常见页面形式

分析HTML,发现无论是普通前台还是Extjs,他们的html有一个共同的特点,具有以下代码:

  <input ..... type="file" ...../>

ok,只要我们使用selenium自带的sendkeys把文件路径(相对绝对无所谓)传给该元素,就可绕过选择窗口直接上传文件.

解决方案诞生了

driver.findElement(XXXXX).sendKeys("filePath");

 

Have a Try

博客园上传图片:driver.findElement(By.name(“file”)).sendKeys(“C:\Users\123\Pictures\a.png”);

QQ邮箱上传附件:driver.findElement(By.name(“UploadFile”)).sendKeys(“C:\Users\123\Pictures\a.png”);

定位元素根据情况而定,不一定用name;文件路径可以使相对路径,大家自行修改就好

 

注意:执行sendKeys的元素一定要符合inputtype=”file”条件,否则就是你没找对上传文件的对象,会上传失败的。

像这样的,一定注意不要上传到前面的那个input上,否则会失败的

 

四、使用pywin32 库(针对非input标签)。

引用文章:https://blog.csdn.net/zyooooxie/article/details/88141601

# 使用win32gui和win32con对弹出的文件窗口进行控制:输入要上传的文件路径,点击打开

# 获取文件弹窗对象【第一个对象句柄,后面的父】
dialog = win32gui.FindWindow('#32770', '打开')       # Chrome 记得配套
# dialog = win32gui.FindWindow('#32770', '文件上传')           # FireFox 记得配套
# IE为'选择要加载的文件',Chrome为'打开',火狐为“文件上传”。

ComboBoxEx32 = win32gui.FindWindowEx(dialog, 0, 'ComboBoxEx32', None)

ComboBox = win32gui.FindWindowEx(ComboBoxEx32, 0, 'ComboBox', None)
# 获取文件路径输入框对象的句柄
Edit = win32gui.FindWindowEx(ComboBox, 0, 'Edit', None)
# 获取 打开button按钮对象
button = win32gui.FindWindowEx(dialog, 0, 'Button', '打开(&O)')
time.sleep(1)
# 输入框输入绝对路径
win32gui.SendMessage(Edit, win32con.WM_SETTEXT, 0, r'd:\60x91.JPG')
time.sleep(3)       # 方便观看过程
# 点击 打开
win32gui.SendMessage(dialog, win32con.WM_COMMAND, 1, button)
time.sleep(3)       # 方便观看过程
自己写的一段代码,验证可行:

__author__ = "MrBean"

#!/usr/bin/env python
# -*- coding:utf-8 -*-

from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver import ActionChains
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait
from time import sleep,time
import win32con,win32api,win32gui
import win32clipboard as w

# driver = webdriver.Chrome()
# driver_type = 1
driver = webdriver.Firefox()
driver_type = 0
driver.maximize_window()

"""
# 读取写入剪切板还可以用pyperclip
# pip install pyperclip
# pyperclip.copy('dsd')#向剪切板发送文本
# pyperclip.paste() #读取剪切板文本
"""
#
# def getClipText():  # 读取剪切板
#     w.OpenClipboard()
#     d = w.GetClipboardData(win32con.CF_TEXT)
#     w.CloseClipboard()
#     return d
#
#
# def setClipText(aString):  # 写入剪切板
#     w.OpenClipboard()
#     w.EmptyClipboard()
#     w.SetClipboardData(win32con.CF_TEXT, aString)
#     w.CloseClipboard()

try:
    """
    #模拟天翼云盘登录
    #切换iframe
    # switch_to_frame可以直接用id或name定位切换
    #如果无id和name,可以通过tag先定位到
    #iframe = driver.find_element_by_tag_name("iframe")
    # drivelr.swirch_to_rrame{ iframe)
    # 当iframe上的操作完后,想重新回到主页面上操作元素,这时候,就可以用switch_to_default_content()方法返回上一层表单
    """
    driver.get("https://cloud.189.cn")

    driver.switch_to.frame("udb_login")
    # 输入账号密码
    driver.find_element_by_id("userName").clear()
    driver.find_element_by_id("userName").send_keys("********")

    sleep(2)

    driver.find_element_by_id("password").clear()
    driver.find_element_by_id("password").send_keys("********")

    sleep(2)

    driver.find_element_by_id("j-login").click()

    # cookie = driver.get_cookies()
    # print(cookie)
    driver.switch_to.default_content()

    sleep(3)
    # 转到新页面
    # curr_window = driver.current_window_handle

    sleep(2)

    file_path = "C:\PyQtProj\ToExe\cardpic.py"

    #针对input标签的文件上传,直接通过send_keys,chrome及firefox皆可用
    # driver.find_element_by_xpath("/html/body/div[3]/div[2]/div[5]/div[1]/div[1]/div/input").send_keys(file_path)

    #针对非input标签或不用send_keys方法,可采用win32gui
    #天翼云盘在firefox上支持有问题,无法通过鼠标悬停在“上传”上显示下拉列表,chrome正常
    if driver_type:
        # 模拟鼠标悬停在“上传”
        upload_btn = driver.find_element_by_id("uploadifive-J_AddFileDiv")
        ActionChains(driver).move_to_element(upload_btn).perform()
        upload_file = driver.find_element_by_id("J_AddFile")
        upload_file.click()
        sleep(1)
        # win32gui
        dialog = win32gui.FindWindow('#32770', '打开')  # chrome的文件对话框
    else:
        upload_btn = driver.find_element_by_id("uploadifive-J_AddFileDiv")
        upload_btn.click()
        sleep(1)
        # win32gui
        dialog = win32gui.FindWindow('#32770', '文件上传')  # firefox的文件对话框

    ComboBoxEx32 = win32gui.FindWindowEx(dialog, 0, 'ComboBoxEx32', None)
    ComboBox = win32gui.FindWindowEx(ComboBoxEx32, 0, 'ComboBox', None)
    Edit = win32gui.FindWindowEx(ComboBox, 0, 'Edit', None)  # 上面三句依次寻找对象,直到找到输入框Edit对象的句柄
    button = win32gui.FindWindowEx(dialog, 0, 'Button', None)  # 确定按钮Button
    win32gui.SendMessage(Edit, win32con.WM_SETTEXT, None, file_path)  # 往输入框输入绝对地址
    win32gui.SendMessage(dialog, win32con.WM_COMMAND, 1, button)  # 按button
    """
    百度网盘模拟登录
    """
    # driver.get("https://pan.baidu.com/")
    #
    # """
    # # 延时2秒,否则会因为浏览器加载页面未完成而出现无法定位到<账号密码登录>:
    # # Unable to locate element: {"method":"id","selector":"TANGRAM__PSP_4__footerULoginBtn"}
    # """
    #
    # """
    # # 方法1:强制等待time.sleep
    # """
    # # sleep(2)
    # #
    # # #模拟点击”账号密码登录“
    # # driver.find_element_by_id("TANGRAM__PSP_4__footerULoginBtn").click()
    #
    # """
    # # 方法2:显式等待WebDriverWait(driver,timeout,poll_frequency=0.5,ignored_exceptions=None)
    # # driver:浏览器驱动
    # # timeout:最长超时时间,默认以秒为单位
    # # poll_frequency:检测的间隔步长,默认为0.5s
    # # ignored_exceptions:超时后的抛出的异常信息,默认抛出NoSuchElementExeception异常。
    # # 与until()或者until_not()方法结合使用
    # # WebDriverWait(driver,10).until(method,message="")
    # # 调用该方法提供的驱动程序作为参数,直到返回值为True
    # # WebDriverWait(driver,10).until_not(method,message="")
    # # 调用该方法提供的驱动程序作为参数,直到返回值为False
    # # 在设置时间(10s)内,等待后面的条件发生。如果超过设置时间未发生,则抛出异常。
    # # 在等待期间,每隔一定时间(默认0.5秒),调用until或until_not里的方法,直到它返回True或False.
    # """
    # element = WebDriverWait(driver, 5, 0.5).until(EC.presence_of_element_located((By.ID, "TANGRAM__PSP_4__footerULoginBtn")))
    # element.click()
    #
    # # 输入账号密码
    # driver.find_element_by_id("TANGRAM__PSP_4__userName").clear()
    # driver.find_element_by_id("TANGRAM__PSP_4__userName").send_keys("********")
    #
    # driver.find_element_by_id("TANGRAM__PSP_4__password").clear()
    # driver.find_element_by_id("TANGRAM__PSP_4__password").send_keys("********")
    #
    # sleep(2)
    #
    # driver.find_element_by_id("TANGRAM__PSP_4__submit").click()

    """
    企业信息门户模拟登录
    """
    # driver.get("http://www.******.com/")
    # element = WebDriverWait(driver, 5, 0.5).until(EC.presence_of_element_located((By.XPATH, "/html/body/div[1]/div/div/div[2]/div[1]/div[1]/div[1]/ul/li[2]/a")))
    # element.click()
    # sleep(1)
    #
    # # 输入账号密码
    # user_name = driver.find_element_by_id("usernameMsg")
    # user_name.clear()
    # user_name.send_keys("********")
    # sleep(1)
    # #display: none点击输入框后变为display: inline-block,报错:could not be scrolled into view(firefox)
    # js = "document.getElementById(\"passwordMsg\").style.display='block';"
    # driver.execute_script(js)
    # password = driver.find_element_by_id("passwordMsg")
    # # print(password.is_displayed())
    # password.clear()
    # password.send_keys("*********")
    # sleep(1)
    # #获取验证码
    # get_code_btn = driver.find_element_by_id("getCode1")
    # get_code_btn.click()
    #
    # code_time = time()
    #
    #
    # key = input('请输入验证码:')
    # js = "document.getElementById(\"verifyCode\").style.display='block';"
    # driver.execute_script(js)
    # driver.find_element_by_id("verifyCode").send_keys(key)
    #
    # # sleep(2)
    #
    # #点击“登录”时报错:Element is not clickable at point (958, 607). Other element would receive the click:
    # #解决办法:通过js来操作点击
    # login_btn = driver.find_element_by_id("login")
    # print(login_btn.is_enabled())
    # js = 'document.getElementById("login").click();'
    # driver.execute_script(js)
except Exception as e:
    print("Get Element Error:%s" % repr(e))
finally:
    sleep(2)
    # 生成快照
    driver.save_screenshot(u"selenium.png")
    driver.quit()

发表回复

您的电子邮箱地址不会被公开。