1. 程式人生 > >selenium之 檔案上傳所有方法整理總結

selenium之 檔案上傳所有方法整理總結

檔案上傳是所有UI自動化測試都要面對的一個頭疼問題,今天博主在這裡給大家分享下自己處理檔案上傳的經驗,希望能夠幫助到廣大被檔案上傳坑住的seleniumer。

首先,我們要區分出上傳按鈕的種類,大體上可以分為兩種,一種是input框,另外一種就比較複雜,通過js、flash等實現,標籤非input

我們分別對這兩種進行分析:

1.input標籤

眾所周知,input標籤是可以直接send_keys的,這裡也不例外,來看程式碼示例:

程式碼:

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

driver = webdriver.Firefox()
driver.get('http://sahitest.com/demo/php/fileUpload.htm'
) upload = driver.find_element_by_id('file') upload.send_keys('d:\\baidu.py') # send_keys print upload.get_attribute('value') # check value driver.quit()

結果:

baidu.py

很明顯,對於input上傳,直接send_keys是最簡單的解決方案。

2.非input型上傳

接下來難度要升級了,對於那些不是input框實現的上傳怎麼辦,這種上傳千奇百怪,有用a標籤的,有用div的,有用button的,有用object的,我們沒有辦法通過直接在網頁上處理掉這些上傳,唯一的辦法就是開啟OS彈框,去處理彈框。

問題又來了,OS彈框涉及的層面已經不是selenium能解決的了,怎麼辦?很簡單,用OS層面的操作去處理唄,到這裡我們基本找到了問題的處理方法。

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

  1. autoIT,藉助外力,我們去呼叫其生成的au3或exe檔案。
  2. Python pywin32庫,識別對話方塊控制代碼,進而操作
  3. SendKeys庫
  4. keybd_event,跟3類似,不過是模擬按鍵,ctrl+a,ctrl+c, ctrl+v…

目前我只知道以上四種辦法,有其他方法的請留言告訴我,讓我學習一下。

我們依次看一下:

1. autoIT

關於autoIT上傳以及引數化的方法我已經在另一篇博文中講過了,請參見。這裡不再贅述。

2.win32gui

廢話不多說,上程式碼先:

程式碼:

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

dr = webdriver.Firefox()
dr.get('http://sahitest.com/demo/php/fileUpload.htm')
upload = dr.find_element_by_id('file')
upload.click()
time.sleep(1)

# win32gui
dialog = win32gui.FindWindow('#32770', u'檔案上傳')  # 對話方塊
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:\\baidu.py')  # 往輸入框輸入絕對地址
win32gui.SendMessage(dialog, win32con.WM_COMMAND, 1, button)  # 按button

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

結果:

baidu.py

在這裡你需要一個非常重要的小工具:Spy++,百度一下有很多,當然你也可以用autoIT自帶的工具,不過沒有這個好用,建議去下一個吧。

而且,你得安裝pywin32的庫,你可以到這裡找到對應你Python版本的庫,注意32位還是64位一定要和你安裝的Python版本對應。

安裝完成之後在【開始選單Python的資料夾】裡看到PyWin32的文件【Python for Windows Documentation】,你能從中找到對應的方法API。

簡單介紹幾個用到的:

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

  • 自頂層視窗開始尋找匹配條件的視窗,並返回這個視窗的控制代碼。
  • lpClassName:類名,在Spy++裡能夠看到
  • lpWindowName:視窗名,標題欄上能看到的名字
  • 程式碼示例裡我們用來尋找上傳視窗,你可以只用其中的一個,用classname定位容易被其他東西干擾,用windowname定位不穩定,不同的上傳對話方塊可能window_name不同,怎麼定位取決於你的情況。

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

  • 搜尋類名和窗體名匹配的窗體,並返回這個窗體的控制代碼。找不到就返回0。
  • hwndParent:若不為0,則搜尋控制代碼為hwndParent窗體的子窗體。
  • hwndChildAfter:若不為0,則按照z-index的順序從hwndChildAfter向後開始搜尋子窗體,否則從第一個子窗體開始搜尋。
  • lpClassName:字元型,是窗體的類名,這個可以在Spy++裡找到。
  • lpWindowName:字元型,是視窗名,也就是標題欄上你能看見的那個標題。
  • 程式碼示例裡我們用來層層尋找輸入框和尋找確定按鈕

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

  • hWnd:整型,接收訊息的窗體控制代碼
  • wParam:整型,訊息的wParam引數
  • lParam:整型,訊息的lParam引數
  • 程式碼示例裡我們用來向輸入框輸入檔案地址以及點選確定按鈕

至於win32api模組以及其他的方法,這裡不進行更多描述,想要了解的自行百度或看pywin32文件。

3.SendKeys

首先要安裝SendKeys庫,可以用pip安裝

pip install SendKeys

程式碼示例:

程式碼:

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

dr = webdriver.Firefox()
dr.get('http://sahitest.com/demo/php/fileUpload.htm')
upload = dr.find_element_by_id('file')
upload.click()
time.sleep(1)

# SendKeys
SendKeys.SendKeys('D:\\baidu.py')  # 傳送檔案地址
SendKeys.SendKeys("{ENTER}") # 傳送回車鍵

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

結果:

baidu.py

通過SendKeys庫可以直接向焦點裡輸入資訊,不過要注意在開啟視窗是略微加一點等待時間,否則容易第一個字母send不進去(或者你可以在地址之前加一個無用字元),不過我覺得這種方法很不穩定,不推薦。

4.keybd_event

win32api提供了一個keybd_event()方法模擬按鍵,不過此方法比較麻煩,也不穩定,所以很不推薦,下面給出部分程式碼示例,如果想要研究,自己百度去學習吧。

...

# 先找一個input框,輸入想要上傳的檔案的地址,剪下到剪貼簿 
video.send_keys('C:\\Users\\Administrator\\Pictures\\04b20919fc78baf41fc993fd8ee2c5c9.jpg')
video.send_keys(Keys.CONTROL, 'a')  # selenium的send_keys(ctrl+a)
video.send_keys(Keys.CONTROL, 'x')  # (ctrl+x)
driver.find_element_by_id('uploadImage').click()  # 點選上傳按鈕,開啟上傳框

# 貼上(ctrl + v)
win32api.keybd_event(17, 0, 0, 0)  # 按下按鍵 ctrl
win32api.keybd_event(86, 0, 0, 0)  # 按下按鍵 v
win32api.keybd_event(86, 0, win32con.KEYEVENTF_KEYUP, 0)  # 升起按鍵 v
win32api.keybd_event(17, 0, win32con.KEYEVENTF_KEYUP, 0)  # 升起按鍵 ctrl
time.sleep(1)

# 回車(enter)
win32api.keybd_event(13, 0, 0, 0)  # 按下按鍵 enter
win32api.keybd_event(13, 0, win32con.KEYEVENTF_KEYUP, 0)  # 升起按鍵 enter

...

是不是很麻煩,當然,你甚至可以用按鍵把整個路徑輸入進去,不過,我想沒人願意這麼做的。而且在此過程中你不能隨意移動滑鼠,不能使用剪貼簿,太不穩定了,所以非常不建議你用這種辦法。。

3.多檔案上傳

接下來還有一種情況值得我們考慮,那就是多檔案上傳。如何上傳多個檔案,當然我們還是往輸入框裡輸入檔案路徑,所以唯一要搞清楚的就是多檔案上傳時,檔案路徑是怎麼寫的。

我來告訴你吧,多檔案上傳就是在檔案路徑框裡用引號括起單個路徑,然後用逗號隔開多個路徑,就是這麼簡單,例如:
“D:\a.txt” “D:\b.txt”
但需要注意的是:只有多個檔案在同一路徑下,才能這樣用,否則是會失敗的(下面的寫法是不可以的):
“C:\a.txt” “D:\b.txt”

接下里找一個例子試試:

程式碼:

# -*- coding: utf-8 -*-

from selenium import webdriver
import win32gui
import win32con
import time

dr = webdriver.Firefox()
dr.get('http://www.sucaijiayuan.com/api/demo.php?url=/demo/20150128-1')

dr.switch_to.frame('iframe')  # 一定要注意frame
dr.find_element_by_class_name('filePicker').click()
time.sleep(1)

dialog = win32gui.FindWindow('#32770', None)
ComboBoxEx32 = win32gui.FindWindowEx(dialog, 0, 'ComboBoxEx32', None)
ComboBox = win32gui.FindWindowEx(ComboBoxEx32, 0, 'ComboBox', None)
Edit = win32gui.FindWindowEx(ComboBox, 0, 'Edit', None)
button = win32gui.FindWindowEx(dialog, 0, 'Button', None)

# 跟上面示例的程式碼是一樣的,只是這裡傳入的引數不同,如果願意可以寫一個上傳函式把上傳功能封裝起來
win32gui.SendMessage(Edit, win32con.WM_SETTEXT, 0, '"d:\\baidu.py" "d:\\upload.py" "d:\\1.html"')
win32gui.SendMessage(dialog, win32con.WM_COMMAND, 1, button)


print dr.find_element_by_id('status_info').text
dr.quit()

結果:

選中3張檔案,共1.17KB。

可見,多檔案上傳並沒有那麼複雜,也很簡單,唯一的區別就是輸入的引數不同而已。autoIT也可以實現,有興趣可以自己試試。

而且我們可以發現一點,就是上面的這個視窗的程式碼跟之前示例中的基本是一樣,說明我們可以把上傳的部分抽出來,寫一個函式,這樣每次要上傳,直接去呼叫函式,傳入引數即可。

看,上傳其實很好處理,你有什麼好的辦法也可以給博主留言,共同交流。