分享

【用EXCEL VBA控制IE】 2

 龙门过客栈 2017-04-01

利用 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./"
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./

上面代码是用来在IE中显示指定的URL的IE对象的Navigate方法的设置方法。第一个参数设置为想要显示的URL「http://www./」,所以「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./"
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子程序。利用 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./"
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./

上面代码是用来在IE中显示指定的URL的IE对象的Navigate方法的设置方法。第一个参数设置为想要显示的URL「http://www./」,所以「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./"
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子程序。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多