1. 程式人生 > >Python selenium win32gui autoIT SendKeys 檔案上傳

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] 獲取的是命令列引數的總數,在上例中 C m d L i n e [ 0 ] = 3 CmdLine[0]=3 ` CmdLine[1]~ C m d L i n e [ 63 ] 1 63 63 CmdLine[63]` 獲取的是命令列引數第1到第63位,這個方式最多隻能獲取63個引數,不過正常情況下是足夠用的 ` 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()

參考:https://blog.csdn.net/huilan_same/column/info/12694