[教えて!VBA] 第1回 処理の途中で待機時間(Sleep)を設けるにはどうすればいいの??

概要

この記事について

かんたんな概要と結論

VBAと他のアプリケーションを連携したり、Webサイトから情報を取得する際に、
待機時間を設ける必要があるケースがあります。
waitsleepの二種類の方法があり、
基本的にどちらを使用しても実現できます。

こんにちは、dedeです。

この記事では、
VBAマクロに関する質問のうち、
皆が疑問に思っているトピックについて解説いたします。

今回は、 処理の途中で待機時間を設けるメリットとその方法について
を解説いたします。

レベル:中級者向け

待機はなぜ必要?

そもそもなぜ待機時間を設ける必要があるのか?

①他のアプリケーションの処理が終わるのを待つため

VBAから他のアプリケーションの処理をトリガーする場合、
アプリケーションの種類によっては同期的に処理できない
(トリガーした方のアプリが終了してから次の処理を行うことができない)場合があります。

1
2Call runSomethingApp()'他のアプリを起動して処理を行う
3
4Set result = getSomethingAppResult()'※※ まだ他のアプリケーションの処理が終わっていないので、想定した結果が得られない
5

そのため、次のようにして
アプリケーションの処理が十分に終えることができるような待機時間を儲けます。

1
2Call runSomethingApp()'他のアプリを起動して処理を行う
3
4Call setTaikiJikan()'待機時間呼び出し関数
5
6Set result = getSomethingAppResult()'待機し、他のアプリが処理完了したので、正常に処理ができる
7

あるいは、次のようにして処理が終わるまでループを回すほうが安全でしょう。

 1
 2Call runSomethingApp()'他のアプリを起動して処理を行う
 3
 4Do
 5    Set result = getSomethingAppResult()'アプリ結果取得
 6    If Not result Is Nothing Then Exit Do'結果が得られれば次の処理へ
 7    If counter > 10 Then
 8        MsgBox "アプリケーションは正常に動作しませんでした"
 9        Exit Function
10    End If
11    Call setTaikiJikanOneSecond()'一秒待機する
12    counter = counter + 1
13Loop
14

VBAから他のアプリケーションを発火させる際は、
同期的に処理できるか、非同期的な処理となるかという点は
注意するべきでしょう。

②Webページのスクレイピングで、ページが表示されるまで待機するため

スクレイピング目的で
プログラムからWebにアクセスした場合、
通常のブラウジングと同じようにページがすべて表示されるまで待機する必要があります。

(下記、IEに対する操作自動化のコード例ですが、他のツールを使用したChromeなどへのスクレイピングでも同様です)

 1Dim objIE As InternetExplorer
 2
 3Set objIE = New InternetExplorer
 4objIE.Visible = True
 5
 6'指定したURLのページを表示する
 7objIE.navigate "https://dede-20191130.github.io/learnerBlog/about/"
 8
 9'完全にページが表示されるまで待機する(想定したHTMLを得られるようにするため)
10Do While objIE.Busy = True Or objIE.readyState <> 4
11    Call setTaikiJikanOneSecond()'一秒待機する
12    DoEvents
13Loop
14
15doSomething()'次の処理
16

待機の方法

Excel VBAとAccess VBAでは別々の方法

待機を実装するための方法が、
ExcelとAccessとで微妙に異なるので、
それぞれ記載したいと思います。

Excel VBA

① Application.Waitを使用する

1Application.Wait(Time)

ApplicationはExcelアプリのインスタンス、
つまり、Excelアプリがもともと持っているWaitという関数を使用するかたちです。

Timeには、Excelで使用できる時間形式が入ります(00:00:10など)。
そのため、ミリ秒単位での待機をしようとすると工夫が必要です。
➩ https://www.higashisalary.com/entry/vba-wait-ms

機能は、指定したTimeまで処理を待機するというものです。

つまり、Now関数と組み合わせることで、
「〇〇秒経過するまで待機」という処理を実現することができます。

1doSomething...
2
3Call Application.Wait(Now + TimeValue("0:00:10"))'10秒だけ待機します。
4
5doSomethingAfter10...

② Windows APIのSleep関数を使用する

 1'モジュールの先頭
 2#If VBA7 Then
 3 Public Declare PtrSafe Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As LongPtr) '64ビットOfficeの場合
 4#Else
 5 Public Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds as Long) '32ビットOfficeの場合
 6#End If
 7
 8Sub SleepTest()
 9    doSomething...
10    Sleep 10000 '10秒だけ待機します。
11    doSomethingAfter10...
12End Sub

Windows API(Application Programming Interface)を使用します。
Windows APIは、Windowsでよく使用される機能がまとまったライブラリです。

上記コード例のように、
モジュールのはじめでPublic Declare......というようにAPIを読み込む宣言をします。

Sleep関数の引数には、ミリ秒の指定が入ります。

Access VBA

① Windows APIのSleep関数を使用する

上記でご説明したように、
SleepはWindows APIであり、Officeの各アプリケーションの固有の機能ではありません。

そのため、
ExcelでもAccessでも(あるいはOutLookなどでも)、読み込みさえしておけば自由に使用することができます。

WaitとSleep、どちらを使う?

Excel以外のOfficeのVBA環境ではSleepを使用すれば問題ないかと思います。

Sleepに対するWaitの優位性としては、
時間の正確さがあります。

Sleepはマシンのプロセッサの時間刻みに依存しており、
マシンごとにわずかに異なる可能性のある時間遅延を計算する恐れがあります。

といっても、待機として用いる際に
そこまで正確な時間計算が求められるかと言われれば怪しいため、
ミリ秒の待機を簡潔に書きたければSleep
外部APIの読み込みの記述が面倒くさければWaitで問題ないでしょう。

デモ(Webサイトのスクレイピング)

 1Sub デモ_本ブログの自己紹介欄から情報取得()
 2    Dim objIE As InternetExplorer
 3    
 4    Set objIE = New InternetExplorer
 5    objIE.Visible = False
 6    objIE.navigate "https://dede-20191130.github.io/learnerBlog/about/" '自己紹介ページを開く
 7
 8    '完全にページが表示されるまで待機する
 9    Do While objIE.Busy = True Or objIE.readyState <> 4
10        Application.Wait (Now + TimeValue("0:00:01")) '//一秒待機
11        DoEvents
12    Loop
13    
14    With objIE.Document.getElementsByTagName("table")(0)
15        Debug.Print .Rows(3).Cells(1).innerText '//githubのURLを取得
16        Debug.Print .Rows(4).Cells(1).innerText '//twitterのURLを取得
17    End With
18    
19    objIE.Quit 'クローズ
20    Set objIE = Nothing
21    
22End Sub
23

上記コードを実行すると、
次のようにイミディエイトウィンドウにURLが表示されます。

1https://github.com/dede-20191130 
2https://twitter.com/D20191130 

関連記事

comments powered by Disqus