みなさん、こんにちは!
テンポよくブログ更新していますタカハシ(@ntakahashi0505)です。
初心者向けエクセルVBAでIEを操作するシリーズの第3回目です。
前回はこちらの記事で
HTMLタグと要素についての説明とHTMLドキュメントの取得についてのお話をしました。
ですが、実際に動かしてみたらエラーが出た…という明らかに中途半端なところで終わらしてしまってごめんなさい。
今回はIEの読み込み待ちの処理を入れることで、そのエラーをバッチリ解決していきますよ。
この処理はVBAでIEを扱う限りはほとんどの場合で必要となる処理ですので、ぜひ覚えて頂ければと思います。
前回のおさらい
前回のプログラムはこちらでした。
Sub MySub()
Dim objIE As InternetExplorer
Set objIE = New InternetExplorer
objIE.Visible = True
objIE.Navigate "https://tonari-it.com/"
Dim htmlDoc As HTMLDocument
Set htmlDoc = objIE.Document
Debug.Print htmlDoc.Title
End Sub
HTMLドキュメントを格納するhtmlDocというオブジェクト変数を用意して、IEで開いたページのHTMLドキュメントをセット。
そして取得したHTMLドキュメントのTitleつまりWEBページのタイトルをイミディエイトウィンドウに表示する、という内容でした。
しかし、実行してみると
こんなエラー画面が出てしまいました。
特定できません、って…
でも安心して下さい。原因はわかっています。
HTMLドキュメントの取得の際に発生するエラーの原因
このエラーの原因を解明していきます。
objIE.Navigate "https://tonari-it.com/"
まずこの命令でIEが指定したURLのページを読み込んでくるのですが、どんなに通信環境がよいところでも少し読み込むまでに時間がかかりますよね?
IEは一生懸命読み込みをしているのですが、VBAはお構いなしに次の命令を実行しに行ってしまいます。
先ほどのエラー画面で「デバッグ」をクリックしてみると
この黄色の箇所でエラーになっていることがわかります。
Set htmlDoc = objIE.Document
ここですね。
何が問題かと言いますとIEがページを読み込み切っていないところで、そのHTMLドキュメントを取得しにいっているのでエラーになっているのです。
要は「存在していないHTMLドキュメントをセットしろ」という命令をしてしまっているということなんです。
無いものはセットできないよ~、てなわけです。
これを避けるために、IEが読み込みが完了したことを確認してから次の処理に移るようにするという対策をとります。
IEブラウザの読み込み待ちの処理
IEのページ読み込みが完了することを待つ処理はこのように書きます。
Do While objIE.Busy = True Or objIE.readyState < READYSTATE_COMPLETE
DoEvents
Loop
条件が2つありまして、このどちらかの条件が満たされている間はDoEventsをして、という処理です。
それぞれ説明をしていきますね。
BusyプロパティでIEが忙しいかどうかを判断
まず、InternetExplorerオブジェクトのBusyプロパティです。
BusyプロパティはIEが忙しければTrue、そうでなければFalseを返します。
忙しいですか?と聞いて、忙しいよと回答されている間はDoEventsすることになります。一生懸命読み込みをしている間は当然Busyになっているということですね。
readyStateプロパティでIEが準備完了かどうかを判断
次に、readyStateプロパティです。
readyStateプロパティはIEの準備状態を数値で返します。
準備完了を表す数値は4で、準備が完了していない間は4未満の数値が返ります。
一方で、「READYSTATE_COMPLETE」はなんだか難しく見えますが、ただの定数で4を表しています。
ですから、IEの準備状態が完了つまり4になるまでDoEventsをするということになります。
DoEvents関数でOSに処理を渡す
DoEventsはOSに処理を渡す命令です。
は?って感じですが、少し説明をしますね。
VBAはループ処理をしている間は、OSにすら処理を渡さずに一生懸命ループをします。つまり他のアプリケーションなどがループが終わるまで全て待ち状態になります。
この命令があるタイミングでVBAは一旦OSに対して「待ってる処理ある?」とお伺いを立てにいき、OSの処理を優先してあげるという行動を取ります。
これがないとブラウザでページが表示されるまでの間、画面が固まったような状態になってしまいますので、このDoEventsを入れているということです。
この説明をさらに詳しく知りたい場合はこちらの記事もご覧頂ければと思います。
IEの読み込み待ち処理を入れて実行
以上、IEの読み込み待ち処理について説明をしてきましたが、これを応用してあれこれやることはあまりないと思いますので、このDo~Loopに関してはnavigateでURLでページを開く処理の次に定型で入れたらよいです。
読み込み待ちを入れたプログラムはこちらです。
Sub MySub()
Dim objIE As InternetExplorer
Set objIE = New InternetExplorer
objIE.Visible = True
objIE.Navigate "https://tonari-it.com/"
Do While objIE.Busy = True Or objIE.readyState < READYSTATE_COMPLETE
DoEvents
Loop
Dim htmlDoc As HTMLDocument
Set htmlDoc = objIE.Document
Debug.Print htmlDoc.Title
End Sub
これを実行すると、イミディエイトウィンドウには
と表示されます。
バッチリですね!
まとめ
このようにエクセルVBAでIEを操作する際には、IEがちゃんと読み込み完了からHTMLドキュメントを取得する必要があります。
これはほとんどの場合で必要になりますので、定型文的にいつも入れるようにするのが良いです。
さて、次回以降いよいよ本格的に取得したHTMLドキュメントから色々な情報を抽出していく方法についてお伝えしていきますね。
まず手始めに、こちらの記事でページ内のリンク先URLをゴソっと取得する方法です。
合わせてご覧くださいね!
連載目次:エクセルVBAでIEを操作してWEBスクレイピング
IEを操作してWEBページのデータを取得して、エクセルのデータとして取り込む、つまりWEBスクレイピングをエクセルVBAで実現します。各種WEBページを課題として様々なデータの取得の仕方を解説していきたいと思います。
- 【エクセルVBAでIE操作】10分で終わるセッティングとWEBページの閲覧確認
- 【エクセルVBAでIE操作】HTMLタグと要素そしてドキュメントの取得
- 【エクセルVBAでIE操作】ブラウザの読み込み待ちをしないとダメなのです
- 【エクセルVBAでIE操作】ページ内のリンク先URLを全部取得する
- 【エクセルVBAでIE操作】ディスクリプションなどの要素をname属性でGetする
- 【エクセルVBAでIE操作】hタグなどの要素をタグ名でGetする
- 【エクセルVBAでIE操作】WEBページのテーブル要素を自動で取得する方法
- 【エクセルVBAでIE操作】WEBページのテーブル要素からセルのデータを取り出す方法
- 【エクセルVBAでIE操作】IEで検索窓にキーワードを入力して送信する方法
- 【エクセルVBAでIE操作】検索結果一覧から記事タイトルを取得する方法
- 【エクセルVBAでIE操作】ブログの記事一覧ページから公開日とカテゴリを取得する
- 【エクセルVBAでIE操作】ページャーをめくって複数ページからデータを取得する
- 【エクセルVBAでIE操作】ユーザー名とパスワードを入力してログインをする
- 【エクセルVBAでIE操作】name属性を利用して画像ボタンをクリックする
- 【エクセルVBAでIE操作】alt属性・src属性を利用して画像ボタンをクリックする
コメント
実務でEXCELVBAからIEを操作する開発をやっている者です。私は当初IEの読み込みをいかに完全に待つことができるのか、方法を見つけ出すのに本当に苦労しました。いろんなサイトで紹介されている方法でもうまくいかず、もういくつか追加する必要があることに気づきました。
まずは、objIE.Documentの読み込みが完了しているか、そしてさらにobjIE内の全要素数が数秒後の要素数と同じになるのか、までチェックしないと私の経験上では順調に次の処理に進むことができませんでした。
しかしこれでも常時正常に動くかは不安です。API Sleepも使いつつなんとか動かすことができている状況です。
以上、情報共有でした。
ryoさん
コメントありがとうございます!
参考になります!
なるほどですね…うまく動作しないときには、この方法も有効ですね。活用させていただきますね!