VBAプログラム開発、スクレイピング・ログイン機能【2-5-1】共通処理をクラスモジュール化する(IE読み込み待ち処理)
ログイン機能をプロシージャ化して書籍登録VBAで扱える様にしました。
そこで、他に作成したVBAについても同様にログイン処理を加えていこうと考えていました。
しかし、毎回一つのモジュール内に同じプロシージャをコピーしています。IE読み込み待ちのモジュールも同様です。
同じ物を何度も使用するのであれば1箇所へまとめておくべきと考えました。
今回はこの対処を行います。
今回の目的
同一処理プロシージャが複数モジュールに配置されているので、一つに統合する
なぜやるか
プログラム作成観点として、同一処理は集約して参照できるようにするため。
やりたいこと
- 標準モジュールから共通プロシージャを集約する方法を検討する
- クラスモジュールを扱う
- IEオブジェクト待機プロシージャをクラスモジュール化する
やったこと
- 実装方法を調べる
- クラスモジュールを作成する
- クラスモジュールに対応する変数を用意する
- クラスモジュールを参照して動作していることを確認する
実施内容
共通化する方法を検討する
プロシージャの共通化をどうにかできないかといろいろ調べていた中で、特にこちらを参考にさせて頂きました、ありがとうございます。
VBAには標準モジュール以外にクラスモジュールというものがあり、こちらで今回意図している物が作成できそうでした。
中身の解説を行うまではなかなか難しいかもしれませんが、上記サイトのヒントを元にまずは実装してみることにしました。
テスト用モジュールで作成する
IE読み込み処理をクラス化する
ログイン処理をプロシージャ化する時にテスト用のモジュールを用意していました。初めのオブジェクト設定とログインだけを行っていた内容となっています。
こちらに、プロシージャの1つとして作成していたIE読み込み待ち処理があるので、これをクラスモジュールへ載せ替えてみます。
クラスモジュールを作成する
まずはクラスモジュールを新規作成します。
今までのコードは全て標準モジュールとして作成していました、今回はクラスモジュールとして作成します。
クラスモジュール名は後のVBAコード内で指定することになります。今回はIE読み込み待ち用なのでwaitObjIEという名前にしました。
# クラスモジュール(新規作成プロシージャ)
Public ObjIE As InternetExplorer
Sub WaitResponse() 'Webブラウザ表示完了待ち
Do While ObjIE.Busy = True Or ObjIE.readyState < READYSTATE_COMPLETE '読み込み待ち
DoEvents
Loop
End Sub
クラスモジュールを作成したら、中身を準備します。IE読み込み用に作成していたプロシージャをそのままコピーです。
そして、クラスモジュール内でObjIE変数を使用したいので、オブジェクト宣言を新たに加えました。
クラスモジュール内宣言としてPublicを使用しています。
ここで宣言したObjIEに今までメインモジュールで宣言していたIEオブジェクトを格納して、WaitResponseプロシージャを実行できるようにします。
クラスモジュール側で動作してくれれば、標準モジュール側に毎回作成していたプロシージャは全てこのクラスモジュールに集約できる…ということになります。
テスト用メインプロシージャから扱える様にする
クラスモジュールは作成できたので、標準モジュール内のプロシージャを対応できるようにします。
IEオブジェクトが対象となるので、オブジェクト設定を確認します。
# テスト用モジュール(メイン処理・編集前)
Sub getURLtest()
'オブジェクト設定
'IEオブジェクト
Dim objIE As InternetExplorer
Set objIE = CreateObject("Internetexplorer.Application")
objIE.Visible = False
今までに使用していたIEオブジェクトの記述です。objIEという変数をIEオブジェクトとして宣言し、IEアプリケーションを扱えるようにしていました。
# テスト用モジュール(メイン処理・編集後)
Sub getURLtest()
'オブジェクト設定
'IEオブジェクト
Dim waitObjIE As waitObjIE
Set waitObjIE = New waitObjIE
Set waitObjIE.ObjIE = CreateObject("Internetexplorer.Application")
waitObjIE.ObjIE.Visible = True
objIE変数はクラスモジュール内で扱うことにしたので、メインとなる処理ではwaitObjIE変数を新たに作成しました。
変数宣言の種類としてAs waitObjIEという同じ名前をつけています、こちらはクラスモジュールwaitObjIEとして使用するために宣言しました。
クラスモジュールを作成してwaitObjIEという名前をつけていました。このクラスモジュールを扱う為の設定です。
混同しそうですが、クラスモジュールの設定を引き出して扱うためにいくつも名前が出てきてしまうことも考慮して、あえて同じにしました。
そして、変数は宣言しただけでは中身が何もないのでNew waitObjIEとして作成しています。
オブジェクト作成後は、IEアプリのオブジェクトが必要となるので格納します。
ここでセット先がwaitObjIE.ObjIEとなっています。
これは、waitObjIEというクラスモジュール内のObjIE変数を指定しています。
# クラスモジュール(新規作成プロシージャ)
Public ObjIE As InternetExplorer
Sub WaitResponse() 'Webブラウザ表示完了待ち
Do While ObjIE.Busy = True Or ObjIE.readyState < READYSTATE_COMPLETE '読み込み待ち
DoEvents
Loop
End Sub
先程のクラスモジュールです。ここにObjIEを宣言しているので、ここにIEオブジェクトが格納されます。これで、クラスモジュール内で操作が可能というながれです。
このあと、テスト用プロシージャでIE読み込みを行うのは初回ログインチェック時にログインフォームにアクセスした時です。
Webアクセスが発生するとIEにHTMLを読み込む処理が発生します。この処理を完了するのを確認するのがIE読み込み待ちとして作成したプロシージャでした。
# テスト用モジュール(メイン処理)
Call CheckLogin(waitObjIE, htmlDoc, Domain, ProcessDir, CheckFirstLogin)
ログイン時の処理となるので、先にログイン処理のプロシージャへ値を引き渡すことになります。
ここで引数の一つ目がwaitObjIEとなっています。いままでobjIEを指定していたので、併せて変更してあります。
# テスト用モジュール(ログインプロシージャ)
'処理実施ページへアクセス後、URL取得
objIE.navigate ProcessPageURL 'IEで開く
waitObjIE.objIE.navigate ProcessPageURL
Call WaitResponse(objIE) '読み込み待ち
waitObjIE.WaitResponse
ResponseURL = objIE.document.URL 'URL取得
ResponseURL = waitObjIE.objIE.document.URL 'URL取得
ログイン処理を行うURL設定後の処理です。
IEオブジェクトはクラスモジュール内のobjIEとして宣言されてオブジェクトが格納されています。
そのためクラスモジュールとして宣言したwaitObjIE内のobjIEに対してnavigateとすることで対象URLへアクセス出来るようにしました。
その後、callとして使用していたWaitResponseを実行します。
クラスモジュール内でプロシージャ化しているので、waitObjIE.WaitResponseとして実行します。
読み込みが完了すれば、オブジェクトからURL取得処理が必要となります。こちらも同様に変数設定を変更しました。
動作確認を行う
後は、クラスモジュールを参照して動作していることを確認します。
IE読み込み待ち処理はwaitObjIE.WaitResponseという標記に変更となっています。
従来のCall WaitResponse()はもうないので、標準モジュール内のWaitResponseプロシージャも削除しました。
そして、処理中のwaitObjIE.WaitResponseを一度コメントアウトしてIE読み込みを待たずに処理させてみます。
エラーになりました。
これはIE読み込み待機をしていないので、HTMLが取得できていない状態で次の処理を行った為です。
コメントアウトを外してIE読み込み完了状態で動作確認することで正常動作となりました。
IE読み込み待ち処理がクラスモジュールで動作しているといえるでしょう。
以上で、プロシージャをクラスモジュールへ載せ替えることができそうです。
IE読み込み処理とログイン処理をそれぞれクラスモジュール化すれば、いままでの処理の共通化ができ、より可読性があがりそうです。
次回からこれで実装を行います。