文件上传是做UI自动化测试时候的一个大问题,尝试了一下网上各种上传文件的方式,以下试验按照使用频率来排名。(多个方法多个思路,你要不想学“茴”字的四种写法,看第一个就够了)

在动手之前,我们要区分出上传按钮的种类,大体上可以分为两种

  • 一种是input框
  • 另外一种就比较复杂,通过js、flash等实现,标签非input

我们分别对这两种进行分析:

1.input标签
众所周知,input标签是可以直接send_keys的,这种情况下就简单粗暴,来看代码示例:

python上传本地图片到小程序 python如何上传文件_上传

python上传本地图片到小程序 python如何上传文件_上传_02

1 from selenium import webdriver
 2 import time
 3 
 4 driver = webdriver.Firefox()
 5 driver.get('url')
 6 driver.find_element_by_name('myfile').send_keys('d:\\test.png')  #输入的是文件的绝对路径。

 2.非input型上传

那么对于那些不是input框实现的上传怎么办,这种上传千奇百怪,有用a标签的,有用div的,有用button的,有用object的,我们没有办法通过直接在网页上处理掉这些上传,唯一的办法就是打开windows的系统弹框,去处理弹框。

问题又来了,Selenium2.0还不能解决掉windows系统弹框的问题,怎么办?很简单,用OS层面的操作去处理呗(谁家的孩子谁家领回家的思维方式在哪里都好用)

大体上有以下四种解决方案:

• Python pywin32库,识别对话框句柄,进而操作
• pywinauto库
• pyautogui库
• autoIT,借助外力,我们去调用其生成的au3或exe文件。

NO 1:pywin32库

1 首先安装pywin32库(命令:pip install pywin32)

2 代码示例

from selenium import webdriver
import win32gui
import win32con

dr = webdriver.Firefox()
dr.get('http://localhost/test/fileupload.html')
dr.find_element_by_id('file').click()# win32gui
dialog = win32gui.FindWindow('#32770', '文件上传')  # 对话框
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, 'd:\\all_money.wmv')  # 往输入框输入绝对地址
win32gui.SendMessage(dialog, win32con.WM_COMMAND, 1, button)  # 按button

这个地方大家其实对识别对话框的句柄有问题,这个在使用autoIt的时候可以解决掉,或者使用Spy++这个小工具。其它的也就是win32gui里面的api调用方式。

NO 2:AutoIt

1 pip install pywinauto

代码如下:

1 from selenium import webdriver
 2 from pywinauto import Desktop
 3 import time
 4 dr=webdriver.Chrome()
 5 
 6 dr.get('url')
 7 dr.maximize_window()
 8 time.sleep(1)
 9 
10 # 操作系统的指令
11 wd = Desktop()
12 open = wd['打开'] #根据名字找到弹出窗口
13 open["Edit"].type_keys("D:\demo.txt") # 在输入框中输入值
14 open["Button"].click()

 NO 3:pyautogui库

from selenium import webdriver
import pyautogui
import time
dr=webdriver.Chrome()

dr.get('url')
dr.maximize_window()

dr.find_element_by_name('myfile').click()
time.sleep(1)
pyautogui.write(r'd:\demo.txt')
time.sleep(1)
pyautogui.press('enter')#回车按键

但是路径内有中文的话这种方法是不支持的,解决方法如下:

from selenium import webdriver
import pyautogui
import pyperclip
import time
dr=webdriver.Chrome()
dr.get('url')
dr.maximize_window()
dr.find_element_by_name('myfile').click()
pyperclip.copy(r'd:\测试.txt')
time.sleep(1)
pyautogui.hotkey('ctrl','v')
time.sleep(1)
pyautogui.press('enter')
time.sleep(2)

 NO 4:AutoIt 

对于OS弹框,上传、下载等,均可以用 autoit 进行处理,同时还可以通过传参对要传的文件进行参数化:

想要参数化传入的参数,可以通过autoit的命令行参数:

D:\ uploadfile.exe param1 "This is an int parameter" 102

在脚本中,可用以下变量获取命令行参数:

$CmdLine[0] ; = 3
$CmdLine[1] ; = param1
$CmdLine[2] ; = "This is an int parameter"
$CmdLine[3] ; = 102
$CmdLineRaw ; = 'param1 "This is a string parameter" 99'

$CmdLine[0] 获取的是命令行参数的总数,在上例中参数有3个。

$CmdLine[1]~$CmdLine[63] 获取的是命令行参数第1到第63位,这个方式最多只能获取63个参数,不过正常情况下是足够用的

$CmdLineRaw 获取的是未拆分的所有参数,是一个长字符串,这种情况下不局限与63个参数

通过autoit的获取对象并编辑脚本:

ControlFocus("文件上传", "", "Edit1")
WinWait("[CLASS:#32770]", "", 10)
ControlSetText("文件上传" ,"", "Edit1", $CmdLine[1])
Sleep(2000)
ControlClick("文件上传", "","Button1");

通过Aut2Exe工具将脚本转成exe文件(uploadfile.exe)
接着就可以使用Python中的os模块来运行这个exe执行程序了。

# -*- coding: utf-8 -*-
from selenium import webdriver
import os
import time

driver = webdriver.Firefox()
driver.get('http://localhost/test/fileupload.html')
driver.find_element_by_id('file').click()
time.sleep(1)

os.system('D:\\Python\\Demo\\uploadfile.exe "d:\\all_money.wmv" ')  # 这里可以对传参进行参数化,我们可以通过py脚本来控制所要上传的文件了

time.sleep(3)
driver.quit()

注意点:关于OS弹框的title,不同浏览器是不一样的,一般firefox是“文件上传”、chrome叫“打开”、而IE则叫“选择要加载的文件”,对于这个问题,你可以写三个不同脚本,
在处理弹框的方法中根据浏览器类型的不同而进行选择,或者每次去获取所有类型弹框,再或者通过参数传入该弹框的名称。 

进阶版:
刚才的几种方法都是上传单个的文件的操作,如果我想上传多个文件怎么办呢?
答案很简单:

多文件上传就是在文件路径框里用引号括起单个路径,然后用空格隔开多个路径,例如:
“D:\allmoney.txt” “D:\allgirls.txt”
注意点为:所有文件最好放于同一路径下,才能这样用,否则是会失败的。(这个还没找到合适的网站测试,稍后添加)