利用Navigate方法用IE訪問某URL
現在,我們來說明一下如何用讓IE啟動並訪問某URL。啟動IE用到了InternetExplorer對象的Navigate方法。
用Navigate方法來顯示某URL的網頁,但是如果要在網頁完全加載完畢之前一直等待還需要其他的處理,接下來我們詳細的說明。
目錄
利用Navigate方法用IE訪問某URL的流程
關於VBA函數、方法、屬性
CreateObject函數
DoEvents函數
Now函數
TimeSerial函數
Navigate方法
Visible屬性
Busy屬性
InternetExplorer對象的ReadyState屬性
Document對象的ReadyState屬性
Refresh方法
利用Navigate方法用IE訪問某URL的例程序
運行結果
說明
改良版的例程序
總結
■利用Navigate方法用IE訪問某URL的流程
本教程首先說明一下將要實現怎樣的處理。個人認為,在把握了整體的處理內容的基礎上,再學習具體的程序寫法可以理解的更為深刻。
下面就是這次的處理流程。
①變量定義
②IE對象生成
※IE對象的方法、屬性變為可以使用的狀態。
③IE對象的顯示。
※將瀏覽器顯示出來。
④訪問指定的URL。
⑤在網頁全部加載完畢之前讓程序進行等待。
※網頁的顯示和加載完畢處理是不同的處理。
■關於VBA函數、方法、屬性
這次需要使用的函數、方法、屬性如下:
CreateObject函數
CreateObject函數是使用自動化機能臨時生成對象的函數。使用此函數,可以把外部的應用程序作為對象來進行操作。
Set 對象變量名 = CreateObject("應用程序名.對象的類型")
DoEvents函數
DoEvents函數是處理的期間對操作系統進行控制的函數。耗時的處理或者循環處理的時候,在處理結束之前讓操作系統不能進行控制。(循環處理的時候,操作系統或者Excel的界面刷新的控制的權限都不會賦予)
因此,使用DoEvents函數可以臨時將操作系統進行控制,從來進行處理。但使用這個函數經常會造成長時間的循環處理或者死循環的情況,過多使用的話,會造成比穩定處理的情況下花更多時間的可能,所以使用時請注意。
DoEvents
Now函數
Now函數,基於正在使用的電腦的系統日期和時間的設置,將現在的日期和時間返回成Variant類型的值。這次使用此函數來解決死循環的問題。
Now
TimeSerial函數
TimeSerial函數,取得參數指定的時、分、秒對應的時間並返回Variant類型的值。這個函數也是用來解決死循環的問題。
TimeSerial(0, 0, 20)
Navigate方法
InternetExplorer 對象的Navigate方法可以讓IE顯示指定的URL。一共有5個參數,但是這次我們只用到其中的必填項URL。
objIE.Navigate ("想讓IE顯示的URL")
Visible屬性
InternetExplorer對象的Visible屬性可以對IE是否顯示進行設置。隱藏的狀態下只是眼睛看不到而已,所以這種情況也可以對IE對象進行操作。
objIE.Visible = True/False
Busy屬性
InternetExplorer對象的Busy屬性用來標示網頁是否正在加載中。True表示加載中,False表示加載完成,但是在實際的處理中也有True→False→True→False反復交替的情況。
比如網站使用了frame或者iframe標簽的時候,最開始的frame加載完成后,一時的返回了False,但是在下一個frame開始加載的時候又變成了True。
其他的比如Javascript等腳步在運行的時候也會出現同樣的現象,所以只用Busy屬性來判斷網頁是否加載完成式不夠的,請理解這一點。
objIE.Busy = True/False
InternetExplorer對象的ReadyState屬性
InternetExplorer對象的ReadyState屬性用來標示IE對象的文檔的加載狀態。加載狀態分為0~4的5個階段,可以用來標示上文中Busy屬性的一部分frame加載完成到所有frame加載完成的狀態。同時,和Busy屬性陪着使用來進行網頁完全加載完成的等待處理,是比較普通的方法。
objIE.readyState = 0~4
Document對象的ReadyState屬性
Document對象的ReadyState屬性用來標示Document對象的文檔的加載狀態。加載裝他分為4個階段,但返回的值是字符串,這點需要注意。這個屬性同樣也可以用來進行網頁完全加載完成的等待處理。
objIE.document.readyState = "uninitialized"/"loading"/"interactive"/"complete"
Refresh方法
InternetExplorer對象的Refresh方法是用來對瀏覽器顯示的網頁進行刷新的方法。瀏覽器加載失敗的時候,這個方法是一個有效的措施。
objIE.Refresh
■利用Navigate方法用IE訪問某URL的例程序
這次的VBA代碼實現了顯示「VBAのIE制御」網站首頁的宏。這是IE控制必須使用的處理,請一定要牢記。
1 Sub sample() 2 3 Dim objIE As InternetExplorer 4 5 'IE(InternetExplorer)對象的創建 6 Set objIE = CreateObject("InternetExplorer.Application") 7 8 'IE(InternetExplorer)顯示 9 objIE.Visible = True 10 11 '顯示指定的URL 12 objIE.Navigate "http://www.vba-ie.net/" 13 14 '在網頁完全加載完成之前等待 15 Do While objIE.Busy = True Or objIE.ReadyState <> 4 16 DoEvents 17 Loop 18 19 End Sub
運行結果
「VBAのIE制御」網站的首頁被顯示出來。
說明
下面我們對上述的VBA代碼進行逐行說明。
Sub sample() Dim objIE As InternetExplorer
這是Sub過程沒有定義參數的例程序。首先,通過Dim語句定義InternetExplorer類型的變量objIE,內存中會分配出一段相應的空間。
通過定義變量,InternetExplorer對象創建的之后就可以使用它的屬性和方法了。
'IE(InternetExplorer)對象的創建 Set objIE = CreateObject("InternetExplorer.Application")
接下來使用引用對象的Set語句和創建對象的CreateObject函數,創建InternetExplorer對象。
'IE(InternetExplorer)的顯示 objIE.Visible = True
這段代碼將InternetExplorer對象的Visible屬性設置成True。Visible屬性可以設置IE的顯示和隱藏,設置為True的時候IE會顯示出來。
默認的情況是設置為False也就是隱藏的狀態,但只是隱藏,IE對象的操作還是可以正常進行,請記住這一點。
'顯示指定的URL objIE.Navigate http://www.vba-ie.net/
上面代碼是用來在IE中顯示指定的URL的IE對象的Navigate方法的設置方法。第一個參數設置為想要顯示的URL「http://www.vba-ie.net/」,所以「VBAのIE制御」網站的首頁就顯示了出來。
'在網頁完全加載完成之前等待 Do While objIE.Busy = True Or objIE.ReadyState <> 4 DoEvents Loop
這段代碼在其他的網站使用者比較多的方法。用Navigate方法雖然可以顯示指定的網頁,但是在瀏覽器將網頁完全加載之前的等待的功能卻沒有。
網頁沒有完全加載完成就進行后續的處理很可能會發生錯誤,或者發生預想之外的處理。因此,在網頁完全加載完成之前有必要讓程序進行等待。(除了Basic Authentication(基本認證))
是否在加載中是用IE對象的Busy屬性和ReadyState屬性進行判斷的。Busy屬性為True代表加載中,而ReadyState屬性為“4”的時候代表加載完成。
下面是ReadyState屬性的返回值一覽,除了4以外的返回值都表示加載中,所以等待處理的循環條件就是“Busy屬性為True或者ReadyState屬性為4以外”。
常量 |
返回值 |
說明 |
READYSTATE_UNINITIALIZED |
0 |
返回值。未完成狀態。 |
READYSTATE_LOADING |
1 |
IE對象加載中的狀態。 |
READYSTATE_LOADED |
2 |
IE對象加載完成,但是不能操作的狀態。 |
READYSTATE_INTERACTIVE |
3 |
IE對象可以操作的狀態。 |
READYSTATE_COMPLETE |
4 |
IE對象的所有數據都加載完成的狀態。 |
我們使用了“滿足某個條件(條件表達式為真)的時候重復處理”功能的Do While~Loop語句,所以在Busy屬性為True或者ReadyState屬性不等於4的期間內,循環都要反復進行。
這里說一些閑話,ReadyState屬性的返回值既可以是常量值,也可以是數值。也就是說把4換成「READYSTATE_COMPLETE」也是一樣的。其他網站如果有類似的代碼的話,請在心里理解為READYSTATE_COMPLETE=4即可。
'在網頁完全加載完成之前等待(使用常量) Do While objIE.Busy = True Or objIE.ReadyState <> READYSTATE_COMPLETE DoEvents Loop
此外,在循環中用到了DoEvents函數。通常的情況下,在循環期間不可以進行操作,但因為我們用到了可以讓操作系統轉讓控制權的DoEvents函數,所以在循環期間仍然可以進行操作。但是,也有可以回避讓機器性能變得非常低的VBA函數。
作為個人對DoEvents函數是否使用的理解,作者認為如果僅僅是對網頁進行遍歷以收集數據、而不對電腦有操作的情況下不需要特意的使用。而且不進行轉讓控制權,也可以通過Esc鍵進行暫停,所以如果只是自己使用不給其他用戶使用的話,也沒有必要使用DoEvents函數。
到現在,我們用兩個屬性來實現了網頁完全加載完成之前的等待處理,但是偶爾也會有瀏覽器永遠在家中的情況發生,俗稱“網頁卡死”。網頁瀏覽器在這種狀態下因為需要在完全加載之前一直反復的等待,所以會陷入死循環。
這個死循環的對策之一,是經過一定的時間之后,對網頁進行再加載(刷新),從而避免了網頁無限等待的狀態。這種情況的代碼如下。
1 Dim timeOut As Date 2 3 '把現在的時間加上20秒 4 timeOut = Now + TimeSerial(0, 0, 20) 5 6 Do While objIE.Busy = True Or objIE.ReadyState <> 4 7 DoEvents 8 Sleep 1 9 If Now > timeOut Then 10 '網頁再加載(刷新) 11 objIE.Refresh 12 timeOut = Now + TimeSerial(0, 0, 20) 13 End If 14 Loop 15 16 '把現在的時間加上20秒 17 timeOut = Now + TimeSerial(0, 0, 20) 18 19 Do While objIE.document.ReadyState <> "complete" 20 DoEvents 21 Sleep 1 22 If Now > timeOut Then 23 '網頁再加載(刷新) 24 objIE.Refresh 25 timeOut = Now + TimeSerial(0, 0, 20) 26 End If 27 Loop
首先,使用Dim語句對日期型(Date)的變量timeOut進行定義。然后,可以返回現在時間的Now函數和把指定日期、時間對應的數值轉換成Date類型的TimeSerial函數,將變量timeOut賦值為處理時間+20秒。上面舉得例子,處理時間如果是10:15:20,變量timeOut的值就會變成多了20秒的10:15:40。
Do While objIE.Busy = True Or objIE.ReadyState <> 4 DoEvents Sleep 1 (省略) Loop
這里使用了剛才說過的Do While~Loop語句來實現網頁完全加載之前的等待處理。循環內部記載了DoEvents函數和Windows API的Sleep函數。
剛才說過,根據DoEvents的處理內容不同來判斷是否應該使用它。Windows API的Sleep函數在循環處理的時候使用,會占據系統的CPU。
因此,設置可以在指定時間內讓處理停止的Windows API的Sleep函數,可以一直CPU的使用率。這里我們設置為“Sleep 1”,參數的單位是微秒,所以會有0.001秒的停止處理。
但是這么做也有弊端,僅僅因為處理的次數變多就會讓運行速度變的緩慢。所以我們讓處理的內容和配置相結合來使用它把。
If Now > timeOut Then '網頁再加載(刷新) objIE.Refresh timeOut = Now + TimeSerial(0, 0, 20) End If
接下來的處理,使用條件分支語句If~Then~Else來實現當變量timeOut中存放的時間已經過去的話,用IE對象的Refresh方法讓頁面進行再加載(刷新),從而避免的無限循環的發生。
頁面再加載(刷新)之后,把處理時間+20秒再次賦給變量timeOut。這樣的話瀏覽器卡死的情況下也可以通過再次加載而避免的無限循環,但是這么做也不是說就完美了。因為容量小的電腦或者打開大容量的網頁的時候,也有發生比通常情況下更花時間的情況。
頁面加載時間一旦超過了20秒,反而會陷入到“頁面再加載(刷新)”的無限循環之后總,所以根據處理的內容不同而選擇合適的等待時間吧。
timeOut = Now + TimeSerial(0, 0, 20) Do While objIE.document.ReadyState <> "complete" DoEvents Sleep 1 If Now > timeOut Then '網頁再加載(刷新) objIE.Refresh timeOut = Now + TimeSerial(0, 0, 20) End If Loop
上面為止的處理對IE對象的狀態進行了檢查,接下來我們對Document對象的狀態進行檢查。
Document對象也就是HTML文檔,所以在進行提取數據或者點擊操作等對HTML文檔進行操作的時候,我們采用更可靠的“HTML文檔是否加載完成的檢查”更加安全。
這里必須注意的是,不同的對象會返回不同的ReadyState值。IE對象的ReadyState屬性在加載完成的時候返回整數值4,但是Document對象的ReadyState屬性的返回值則是字符串"complete"。
下面是Document對象的ReadyState屬性的返回值一覽,通過這個表格可以知道和IE對象的ReadyState屬性的區別。
返回值 |
說明 |
"uninitialized" |
默認值。加載之前。 |
"loading" |
Document對象加載中。 |
"interactive" |
Document對象加載中,可以操作 |
"complete" |
Document對象加載完成 |
類似這樣的擁有同樣的屬性和方法,但是不同的對象返回值也不同的情況,本教程會明確記載是哪些對象的屬性或者方法。認識到這點之后,會對本教程的理解更加的容易。
此外,如果不理解對象、集合、方法、屬性等VBA的基礎只是,學習「VBA初心者入門」教程之后,再來挑戰控制IE的教程,理解的程度會加深。所以請閱讀此初級教程。
大大佐注:VBA初級教程暫時未翻譯,請參考其他基礎教程。
回到剛才的話題,Document對象的加載狀態檢查,除了ReadyState屬性的設定值不同之外,其他都是同樣的處理。這部分代碼也是加載完成之前一直重復進行處理,所以當跳出循環時就表示頁面已經全部加載完成。
這次我們介紹了使用IE對象的Refresh方法避開加載完成之前處理的無限循環,但是有時候我們也想在頁面並未完全加載完成之后就要結束處理。
這種情況下,不使用Refresh方法,而使用跳轉語句GoTo,讓程序在20秒之后就跳出循環,也是一種解決方法。這么做的話,經過一定的時間之后肯定會進行下面的處理,所以也可以說是一種強制執行后面處理的方法。
1 Dim timeOut As Date 2 3 '把現在的時間加上20秒 4 timeOut = Now + TimeSerial(0, 0, 20) 5 6 Do While objIE.Busy = True Or objIE.readyState <> 4 7 DoEvents 8 Sleep 1 9 If Now > timeOut Then 10 '跳轉到label01 11 GoTo label01 12 End If 13 Loop 14 15 label01: 16 17 '把現在的時間加上20秒 18 timeOut = Now + TimeSerial(0, 0, 20) 19 20 Do While objIE.document.ReadyState <> "complete" 21 DoEvents 22 Sleep 1 23 If Now > timeOut Then 24 '跳轉到label02 25 GoTo label02 26 End If 27 Loop 28 29 label02:
■改良版的例程序
下面是網頁加載完成之前進行等待處理的VBA代碼。這次我們不得已使用了 Windows API的Sleep函數,這也是我們正在考慮的問題。關於Windows API我們會改時間做說明,這次的話我們先好好理解一下下面代碼的處理內容吧。
1 #If VBA7 Then 2 Private Declare PtrSafe Sub Sleep Lib "kernel32" (ByVal ms As LongPtr) 3 #Else 4 Private Declare Sub Sleep Lib "kernel32" (ByVal ms As Long) 5 #End If 6 7 Sub sample() 8 9 Dim objIE As InternetExplorer 10 Dim timeOut As Date 11 12 'IE(InternetExplorer)對象的創建 13 Set objIE = CreateObject("InternetExplorer.Application") 14 15 16 'IE(InternetExplorer)顯示 17 objIE.Visible = True 18 19 '讓IE瀏覽器顯示指定的URL 20 objIE.navigate "http://www.vba-ie.net/" 21 22 '頁面完全加載完成之前等待 23 timeOut = Now + TimeSerial(0, 0, 20) 24 25 Do While objIE.Busy = True Or objIE.readyState <> 4 26 DoEvents 27 Sleep 1 28 If Now > timeOut Then 29 objIE.Refresh 30 timeOut = Now + TimeSerial(0, 0, 20) 31 End If 32 Loop 33 34 timeOut = Now + TimeSerial(0, 0, 20) 35 36 Do While objIE.document.ReadyState <> "complete" 37 DoEvents 38 Sleep 1 39 If Now > timeOut Then 40 objIE.Refresh 41 timeOut = Now + TimeSerial(0, 0, 20) 42 End If 43 Loop 44 45 End Sub
■總結
本節課程我們說明了包括在網頁顯示的時候必須的注意事項等內容。對處理的內容一條一條的理解的話是沒有那么困難。這節課也是基礎中的基礎,一定要好好理解。
下節課,我們會講解程序的Sub子程序。