selenium之 文件上傳方法

文件上傳是全部UI自動化測試都要面對的一個頭疼問題php

首先,咱們要區分出上傳按鈕的種類,大致上能夠分爲兩種,一種是input框,另一種就比較複雜,經過jsflash等實現,標籤非inputhtml

咱們分別對這兩種進行分析:python

1.input標籤web

衆所周知,input標籤是能夠直接send_keys的windows

代碼:api

# -*- 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()

  

結果:ide

baidu.py函數

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

2.input型上傳學習

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

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

大致上有如下幾種解決方案:

  1. autoIT,藉助外力,咱們去調用其生成的au3或exe文件。
  2. Python pywin32庫,識別對話框句柄,進而操做(安裝包下載路徑: https://sourceforge.net/projects/pywin32/?source=typ_redirect)
  3. SendKeys庫
  4. keybd_event,跟3相似,不過是模擬按鍵,ctrl+a,ctrl+c, ctrl+v…

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

咱們依次看一下:

1. autoIT

關於autoIT上傳以及參數化的方法我已經在另外一篇博文中講過了,請參見selenium之 autoit命令行參數 。這裏再也不贅述。

2.win32gui

廢話很少說,上代碼先:

示例網址:http://www.sahitest.com/demo/php/fileUpload.htm

代碼:

# -*- 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:整型,接收消息的窗體句柄
  • Msg:整型,要發送的消息,這些消息都是windows預先定義好的,能夠參見系統定義消息(System-Defined Messages)
  • wParam:整型,消息的wParam參數
  • lParam:整型,消息的lParam參數
  • 代碼示例裏咱們用來向輸入框輸入文件地址以及點擊肯定按鈕

至於win32api模塊以及其餘的方法,這裏不進行更多描述,想要了解的自行百度或看pywin32文檔。

3.SendKeys

首先要安裝SendKeys庫,能夠用pip安裝

pip install SendKeys

代碼示例:

示例網址:http://www.sahitest.com/demo/php/fileUpload.htm

代碼:

# -*- 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」

接下里找一個例子試試:

示例網址:http://www.sucaijiayuan.com/api/demo.php?url=/demo/20150128-1

代碼:

# -*- 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也能夠實現,有興趣能夠本身試試。

並且咱們能夠發現一點,就是上面的這個窗口的代碼跟以前示例中的基本是同樣,說明咱們能夠把上傳的部分抽出來,寫一個函數,這樣每次要上傳,直接去調用函數,傳入參數便可。

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

相關文章
相關標籤/搜索