Selenium+Python上傳文件方法大全

文件上傳是做UI自動(dòng)化測試時(shí)候的一個(gè)大問題,嘗試了一下網(wǎng)上各種上傳文件的方式,以下試驗(yàn)按照使用頻率來排名。(多個(gè)方法多個(gè)思路,你要不想學(xué)“茴”字的四種寫法,看第一個(gè)就夠了)

孔乙己茴香豆.jpg

環(huán)境準(zhǔn)備:

  • 一個(gè)可以帶有上傳文件按鈕的網(wǎng)頁(把以下代碼拷貝到一個(gè)新建文本文檔中,可以取名為fileupload.html)
 <html>

<body>

<form name="form1" action="fileUpload.php" method="post" enctype="multipart/form-data">
<label for="file">File:</label>
<input type="file" name="file" id="file" /> 
<br />
<input type="hidden" name="multi" value="false"/>
<input type="submit" name="submit" value="Submit Single" />
</form>


<form action="fileUpload.php" method="post" enctype="multipart/form-data">
<label for="file2">File[]:</label>
<input type="file" name="file[]" id="file2" /> 
<br />
<label for="file3">File[]:</label>
<input type="file" name="file[]" id="file3" /> 
<br />
<input type="hidden" name="multi" value="true"/>
<input type="submit" name="submit" value="Submit Array" />
</form>

<script>
function setAction(){
    document.form2.action = "fileUpload.php";
}
</script>

<form name="form2" action="" method="post" enctype="multipart/form-data" onsubmit="setAction()">
<label for="file">File:</label>
<input type="file" name="file" id="file4" /> 
<br />
<input type="hidden" name="multi" value="false"/>
<input type="submit" name="submit" value="Submit Single" />
</form>

</body>
</html>
  • 把這個(gè)文件扔到xampp的/htdocs/test目錄下(test目錄是自己建的)
12.png

在動(dòng)手之前,我們要區(qū)分出上傳按鈕的種類,大體上可以分為兩種

  • 一種是input框
  • 另外一種就比較復(fù)雜,通過js、flash等實(shí)現(xiàn),標(biāo)簽非input

我們分別對(duì)這兩種進(jìn)行分析:
1.input標(biāo)簽
眾所周知,input標(biāo)簽是可以直接send_keys的,這種情況下就簡單粗暴(專一 一點(diǎn),這種已經(jīng)就很好了),來看代碼示例:

from selenium import webdriver
import time

driver = webdriver.Firefox()
driver.get('http://localhost/test/fileupload.html')
upload = driver.find_element_by_id('file')
time.sleep(12)
upload.send_keys('d:\\all_money.wmv')  # send_keys
print (upload.get_attribute('value'))  # check value

driver.quit()

控制臺(tái)結(jié)果輸出:

"C:\Program Files\Python35-32\python.exe" D:/Python/Demo/fileupload.py
all_money.wmv

2.非input型上傳

那么對(duì)于那些不是input框?qū)崿F(xiàn)的上傳怎么辦,這種上傳千奇百怪,有用a標(biāo)簽的,有用div的,有用button的,有用object的,我們沒有辦法通過直接在網(wǎng)頁上處理掉這些上傳,唯一的辦法就是打開windows的系統(tǒng)彈框,去處理彈框。

問題又來了,Selenium2.0還不能解決掉windows系統(tǒng)彈框的問題,怎么辦?很簡單,用OS層面的操作去處理唄(誰家的孩子誰家領(lǐng)回家的思維方式在哪里都好用)

大體上有以下四種解決方案:

  • Python pywin32庫,識(shí)別對(duì)話框句柄,進(jìn)而操作
  • SendKeys庫
  • autoIT,借助外力,我們?nèi)フ{(diào)用其生成的au3或exe文件。
  • keybd_event,跟第一種類似,不過是模擬按鍵,ctrl+a,ctrl+c, ctrl+v…
    目前只知道以上四種辦法,有其他方法的請(qǐng)留言,歡迎拍磚和討論。

NO 1:pywin32庫
1 首先安裝pywin32庫(命令:pip install pywin32)
2 代碼示例

from selenium import webdriver
import win32gui
import win32con
import time

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

# win32gui
dialog = win32gui.FindWindow('#32770', '文件上傳')  # 對(duì)話框
ComboBoxEx32 = win32gui.FindWindowEx(dialog, 0, 'ComboBoxEx32', None)
ComboBox = win32gui.FindWindowEx(ComboBoxEx32, 0, 'ComboBox', None)
Edit = win32gui.FindWindowEx(ComboBox, 0, 'Edit', None)  # 上面三句依次尋找對(duì)象,直到找到輸入框Edit對(duì)象的句柄
button = win32gui.FindWindowEx(dialog, 0, 'Button', None)  # 確定按鈕Button

win32gui.SendMessage(Edit, win32con.WM_SETTEXT, None, 'd:\\all_money.wmv')  # 往輸入框輸入絕對(duì)地址
win32gui.SendMessage(dialog, win32con.WM_COMMAND, 1, button)  # 按button

print (upload.get_attribute('value'))
dr.quit()

控制臺(tái)結(jié)果輸出:

"C:\Program Files\Python35-32\python.exe" D:/Python/Demo/fileupload.py
all_money.wmv

這個(gè)地方大家其實(shí)對(duì)識(shí)別對(duì)話框的句柄有問題,這個(gè)在使用autoIt的時(shí)候可以解決掉,或者使用Spy++這個(gè)小工具。其它的也就是win32gui里面的api調(diào)用方式。

常用的:

win32gui.FindWindow(lpClassName=None, lpWindowName=None):

自頂層窗口開始尋找匹配條件的窗口,并返回這個(gè)窗口的句柄。
lpClassName:類名,在Spy++里能夠看到
lpWindowName:窗口名,標(biāo)題欄上能看到的名字
代碼示例里我們用來尋找上傳窗口,你可以只用其中的一個(gè),用classname定位容易被其他東西干擾,用windowname定位不穩(wěn)定,不同的上傳對(duì)話框可能window_name不同,怎么定位取決于你的情況。

win32gui.FindWindowEx(hwndParent=0, hwndChildAfter=0, lpszClass=None, lpszWindow=None)

搜索類名和窗體名匹配的窗體,并返回這個(gè)窗體的句柄。找不到就返回0。
hwndParent:若不為0,則搜索句柄為hwndParent窗體的子窗體。
hwndChildAfter:若不為0,則按照z-index的順序從hwndChildAfter向后開始搜索子窗體,否則從第一個(gè)子窗體開始搜索。
lpClassName:字符型,是窗體的類名,這個(gè)可以在Spy++里找到。
lpWindowName:字符型,是窗口名,也就是標(biāo)題欄上你能看見的那個(gè)標(biāo)題。
代碼示例里我們用來層層尋找輸入框和尋找確定按鈕

win32gui.SendMessage(hWnd, Msg, wParam, lParam)

hWnd:整型,接收消息的窗體句柄
Msg:整型,要發(fā)送的消息,這些消息都是windows預(yù)先定義好的,可以參見系統(tǒng)定義消息(System-Defined Messages)
wParam:整型,消息的wParam參數(shù)
lParam:整型,消息的lParam參數(shù)
代碼示例里我們用來向輸入框輸入文件地址以及點(diǎn)擊確定按鈕。

NO 2:AutoIt
對(duì)于OS彈框,上傳、下載等,均可以用 autoit 進(jìn)行處理,同時(shí)還可以通過傳參對(duì)要傳的文件進(jìn)行參數(shù)化:

想要參數(shù)化傳入的參數(shù),可以通過autoit的命令行參數(shù):

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

在腳本中,可用以下變量獲取命令行參數(shù):

$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] 獲取的是命令行參數(shù)的總數(shù),在上例中參數(shù)有3個(gè)。

$CmdLine[1]~$CmdLine[63] 獲取的是命令行參數(shù)第1到第63位,這個(gè)方式最多只能獲取63個(gè)參數(shù),不過正常情況下是足夠用的

$CmdLineRaw 獲取的是未拆分的所有參數(shù),是一個(gè)長字符串,這種情況下不局限與63個(gè)參數(shù)

通過autoit的獲取對(duì)象并編輯腳本:

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

通過Aut2Exe工具將腳本轉(zhuǎn)成exe文件(uploadfile.exe)
接著就可以使用Python中的os模塊來運(yùn)行這個(gè)exe執(zhí)行程序了。

# -*- 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" ')  # 這里可以對(duì)傳參進(jìn)行參數(shù)化,我們可以通過py腳本來控制所要上傳的文件了

time.sleep(3)
driver.quit()

執(zhí)行效果如下:

uploadcamrec.gif

注意點(diǎn):關(guān)于OS彈框的title,不同瀏覽器是不一樣的,一般firefox是“文件上傳”、chrome叫“打開”、而IE則叫“選擇要加載的文件”,對(duì)于這個(gè)問題,你可以寫三個(gè)不同腳本,在處理彈框的方法中根據(jù)瀏覽器類型的不同而進(jìn)行選擇,或者每次去獲取所有類型彈框,再或者通過參數(shù)傳入該彈框的名稱。

NO 3:Sendkeys庫
通過SendKeys庫可以直接向焦點(diǎn)里輸入信息,不過要注意在打開窗口是略微加一點(diǎn)等待時(shí)間,否則容易第一個(gè)字母send不進(jìn)去(或者你可以在地址之前加一個(gè)無用字符),這種方法很不穩(wěn)定,不推薦。

NO 4:keybd_event
win32api提供了一個(gè)keybd_event()方法模擬按鍵,不過此方法比較麻煩,也不穩(wěn)定,所以很不推薦


進(jìn)階版:
剛才的幾種方法都是上傳單個(gè)的文件的操作,如果我想上傳多個(gè)文件怎么辦呢?
答案很簡單:

多文件上傳就是在文件路徑框里用引號(hào)括起單個(gè)路徑,然后用空格隔開多個(gè)路徑,例如:
“D:\allmoney.txt” “D:\allgirls.txt”
注意點(diǎn)為:所有文件最好放于同一路徑下,才能這樣用,否則是會(huì)失敗的。(這個(gè)還沒找到合適的網(wǎng)站測試,稍后添加)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容