情景:
在用selenium進行web頁面自動化時,時不時會遇到上傳附件的情況,常見的情況就是一個上傳按鈕,點擊后彈出windows窗口,選擇文件后上傳,如下圖1所示
圖1
這種情況超出了selenium的能力范圍,需要借助其他工具來實現,這里介紹AutoIt這個工具:
1.下載並安裝
進入AutoIt官網,選擇AutoIt -> Downloads,如圖2:
圖2
然后選擇Full Installation版本,里面包含了所需的所有工具,如圖3:
圖3
下載后直接安裝即可。
2.探測控件
(1).首先從“開始”菜單里找到"Au3Info_x64.exe" 打開,如圖4:
圖4
(2).打開需要上傳的頁面,點擊上傳,彈出上傳窗口,如上面圖1所示
(3).在AutoIt上面,用鼠標按住Finder Tool不放(鼠標圖標變成一個輪子的樣子),移動到上傳窗口的文本輸入框中,然后松開,如圖5
圖5
松開后查看探測結果,如圖6:
圖6
主要關注圖6中紅色標注的信息:
窗口標題,即Title,圖中是“文件上傳”
窗口的class,圖中是32770
控件的類型以及編號,圖中類型是Edit,編號(Instance)是1,表明是窗口中第一個文本輸入框
類似地,重復上面的一步,獲取“打開”按鈕的信息,圖如7:
圖7
由於是同一個窗口,因此標題和class都和上面的一樣,不同的是,這里的"打開"按鈕的類型是Button,編號為1(如果是“取消”按鈕,編號就是2)。獲取到這些必須信息后,就可以開始編寫腳本了。
3.編寫腳本
從開始菜單中打開SciTE Script Editor,編寫如圖8的內容:
圖8
腳本內容如下,分號開頭的是注釋:
; 等待5秒鍾,讓上傳窗口出現
WinWait("[CLASS:#32770]","",5)
;把輸入焦點定位到上傳輸入文本框中,類型為Edit,編號為1,也就是上面獲取到內容
ControlFocus("文件上傳", "","Edit1")
;在文件名那里,輸入需要上傳的文件絕對路徑
ControlSetText("文件上傳", "", "Edit1", 'D:\files\file_name')
;等待上傳時間,單位是毫秒 1秒 = 1000 毫秒,文件大的話需要設置長點
Sleep(5000)
;點擊"打開"按鈕,也就是上傳,完成整個上傳過程
ControlClick("文件上傳", "","Button1");
保存為.au3腳本,然后在瀏覽器中點擊上傳,使上傳窗口出現,如圖1所示,然后在SciTe Scripts Editor里面選Tools -> Go (或直接按F5) 即可看到自動上傳效果。
4.轉換為exe文件
在開始菜單中打開"Compile sctrip to .exe x64"(32位的機器選x86),然后選擇要裝換的.au3文件和輸出的exe文件路徑和名稱,最后點擊下面的"Convert"即可,如圖9:
圖9
5.使用python調用
使用配Python調用是,首先用python控制selenium,打開上傳窗口(圖1),然后用
import os
os.system(r'C:\Users\dell\Desktop\no_argument.exe') #這里是保存的exe文件,根據自己的實際情況修改
然后跑python腳本,即可完成文件上傳。
6.參數化
上面的過程雖然可以上傳文件,但是路徑、文件名都是寫死在腳本里面的,如果要上傳其它路徑、其它文件,就要要重新修改腳本,編譯成exe文件;如果上傳多個文件,每個文件都要寫個腳本然后轉成exe
那豈不是很蛋疼? 參數化可以解決這個問題。
控件探測過程還和原來一樣,腳本參數化只需要修改腳本,如圖10:
圖10
腳本內容如下,注意黃色背景的內容:
; 等待5秒鍾,讓上傳窗口出現
WinWait("[CLASS:#32770]","",5)
;把輸入焦點定位到上傳輸入文本框中
ControlFocus("文件上傳", "","Edit1")
;判斷是否有參數
IF $CmdLine[0] > 0 Then ;有參數
$file = $CmdLine[1]
;Else ;無參數,傳遞默認的文件
;$file = 'D:\work\1.png'
EndIf
;在文件名那里,使用參數
ControlSetText("文件上傳", "", "Edit1", $file)
;等待上傳時間,單位是毫秒 1秒 = 1000 毫秒
Sleep(5000)
;點擊"打開"按鈕,也就是上傳
ControlClick("文件上傳", "","Button1");
同樣保存為.au3文件,然后打開上傳窗口,按F5運行,成功后轉換為exe文件
注意:
參數化之后,調用時需要傳遞參數,再用os.system(r'C:\Users\dell\Desktop\upload.exe 參數') 這種絕對路徑調用,並不能生效,解決辦法是把生成的exe文件,放到PATH里面,然后不帶路徑,直接調用
os.system('upload.exe upload_filename') 即可(過程中會有命令提示符窗口一閃而過,請無視)。
舉一反三:如果連窗口id,文本輸入框都變化,該怎么辦?如果上傳的文件比較到,需要等待較長時間怎么辦?
提示:控件標識,比如類型、編號,等待時間,都可以參數化。下提供一個大體上通用(不敢說所有情況都適用)的腳本以及調用函數:
7.進一步參數化
把上面參數化的腳本修改為如圖11的內容:
圖11
其中第3~8行,分別對應的是:
windowTitle是上傳窗口的標題,對應圖6上面的Title,“文件上傳” (這個跟瀏覽器有關,firefox可能叫做“上傳文件”,chrome則可能是“打開”)
windowID是上傳窗口的標識ID,對應圖6上面的class,"#32770" (這個ID好像基本都是一樣的,不過不是很肯定)
windowText是上傳窗口的文本輸入框,對應圖6上面的class和instance,這里把他們合並到一起了
windowButton是上傳窗口的“打開”按鈕,這里把class和instance也合並到一起
uploadTime就是上傳時等待的時間,如果上傳的文件比較大或者網速比較慢,這個時間需要設置長一點,單位是秒
把這個腳本轉換為exe文件,比如upload_file.exe,然后放入PATH中,
使用下面代碼調用:
os.system('%s "%s" "%s" "%s" "%s" %d %s' % ('upload_file.exe','文件上傳','32770','Edit1','Button1',2,r'D:\testfile\thefile'))
#注意上面這個寫法中,除了uploadTime需要傳遞為整數之外,其他參數都要傳遞為字符串
下面提供一個現成的函數,有興趣的話可以試試:
(別問我為什么只貼圖不貼內容。 紙上得來終覺淺,絕知此事要躬行。手動敲一遍比看十遍學得都快!怎么樣 !
說明:
第一個參數dirver是瀏覽器對象,第二個就是我們剛編譯成的exe文件,第三個是要上傳的文件所在的目錄,第四個是要上傳的文件,如果有多個,需要放在列表中,比如['file1','file2']
考慮到windows上大部分上傳窗口都是一樣的,后面幾個采用了默認參數
需要注意的是,第17、18行獲取上傳按鈕並點擊,需要修改成具體的情況,而且上傳一個文件后,之前獲取到的upload_button這個元素句柄失效,必須重新用find_element獲取一次
下面是調用的示例(ff是生成的瀏覽器對象,我用是firefox,叫做ff):
upload_files(ff,'upload_file.exe',r'D:\Work\測試圖片','php.jpg') #上傳單個文件
upload_files(ff,'upload_file.exe',r'D:\Work\測試圖片','redhat.jpg')
upload_files(ff,'upload_file.exe',r'D:\Work\測試圖片',['redhat.jpg','ubuntu.jpg','php.jpg','linux.png']) #上傳多個文件
upload_files(ff,'upload_file.exe',r'D:\tmp','data.zip',uploadTime=30) #zip文件比較大,設置上傳時間為30秒
upload_files(ff,'upload_file.exe',r'D:\tmp',['Git使用.docx','debian.jpg','vim.jpg'],uploadTime=1) #jpg文件比較小,設置上傳時間1秒
當然,如果你的上傳窗口跟這個完全不同,最完整的情況就是:
upload_files(ff,'upload_file.exe',r'D:\tmp',['Git使用.docx','debian.jpg','vim.jpg'],windowTitle="打開",windowID="12345",windowText="Edit100",windowButton="Btn100",uploadTime=1) #jpg文件比較小,設置上傳時間1秒
不過你要是提供了所有的參數,大可以這樣:
upload_files(ff,'upload_file.exe',r'D:\tmp',['Git使用.docx','debian.jpg','vim.jpg'],"打開","12345","Edit100","Btn100",1)
如果不知道為什么的話,補補Python去吧。
至於下載,過程和上傳相反,稍后補充。