Python selenium win32gui autoIT SendKeys 檔案上傳
selenium對網頁進行UI自動化時經常會遇到作業系統彈框,比如上傳、下載框,對這種彈框,selenium無法處理。
上傳按鈕有簡單的input按鈕,還有js、flash等複雜按鈕,針對不同的按鈕,我們有不同的自動化方法。
input標籤直接send_keys
以網址:http://www.sahitest.com/demo/php/fileUpload.htm為示例。
# -*- 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()
對於input上傳,直接send_keys是最簡單的解決方案。
win32gui上傳檔案
先用Spy++
找到視窗類和名。
# -*- 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()
其中用到幾個重要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引數
程式碼示例裡我們用來向輸入框輸入檔案地址以及點選確定按鈕
win32ui的其他函式和用法,參見文件:
https://github.com/mhammond/pywin32
SendKeys
安裝:
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()
autoIT作業系統彈框
用autoIT可以操控很多控制元件。
想要引數化傳入的引數,可以通過autoit
的命令列引數:
D:\> myProg.exe param1 "This is a string parameter" 99
結果:
$CmdLine[0] ; = 3
$CmdLine[1] ; = param1
$CmdLine[2] ; = "This is a string parameter"
$CmdLine[3] ; = 99
$CmdLineRaw ; = 'param1 "This is a string parameter" 99'
$CmdLine[0]
獲取的是命令列引數的總數,在上例中
CmdLine[1]~
CmdLineRaw` 獲取的是未拆分的所有引數,是一個長字串,這種情況下不侷限與63個引數
通過autoit的獲取物件並編輯指令碼:
ControlFocus("檔案上傳", "", "Edit1")
WinWait("[CLASS:#32770]", "", 10)
ControlSetText("檔案上傳" ,"", "Edit1", $CmdLine[1])
Sleep(2000)
ControlClick("檔案上傳", "","Button1");
通過Aut2Exe工具將指令碼轉成exe檔案(upfile.exe)
我們先通過命令列試試,開啟網頁上傳彈框,然後在cmd中執行該指令碼:
D:\> upfile.exe "D:\1.html"
接下來就是用Python用os模組來呼叫該檔案了:
# -*- coding: utf-8 -*-
from selenium import webdriver
import os
import time
driver = webdriver.Firefox()
driver.get('http://www.sahitest.com/demo/php/fileUpload.htm')
driver.find_element_by_id('file').click()
time.sleep(1)
# 這裡可以對傳參進行引數化,我們可以通過py指令碼來控制所要上傳的檔案了
os.system('D:\\upfile.exe "D:\\1.html"')
time.sleep(3)
driver.quit()
還可以用Python版的autoIT:
https://github.com/jacexh/pyautoit
多檔案上傳
多檔案上傳就是在檔案路徑框裡用引號括起單個路徑,然後用空格隔開多個路徑,並且多個檔案在同一路徑下。如下格式:
"D:\\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()