概要

本サイトには、すでにWeb ページをダウンロードする方法〜 MSXML 編〜という類似トピックが存在します。

そちらでは、WebBrowser コントロールを使用せずに、Web ページをテキストファイルとして取得し、正規表現を使用してソースを独自解析することで情報を取得する方法について解説しています。

これはこれで、有効です。特に目的のデータの位置をキーワードなどで容易に特定できる場合は、最も効率的でしょう。

しかし一方で、対象データが遍在しているような場合では、複雑なソースの解析に HTML DOM (HTML Document Object Model) が威力を発揮する場合も有ります。

だったら最初から WebBrowser コントロールを使用すればよい話なのですが、ここにジレンマが存在します。

DOM は使いたい。

でも表示したいわけではないから、WebBrowser コントロールは要らない。

かと言って、WebBrowser コントロール無しでどうやって DOM にアクセスできるのか分からない。

# そんなジレンマ、ワシだけか (^ ^;)

結局、非表示にした WebBrowser コントロールを挿入するという話に落ち着くのでしょうか。

いやいや、常連さんならすぐに予想が付く通り、そんな話になるくらいなら YU-TANG は最初からネタになんかしませんて。

ここでは WebBrowser コントロールを使用せずに VBA 上から DOM にアクセスする方法を提示します。

※ 本トピックでは、HTML DOM オブジェクトを手っ取り早くオンメモリで取得する簡単な方法について解説しています。単にファイルとして保存できれば事足りる場合や、より詳細な制御を行いたい場合には、本手法は適していません。その場合は、先に関連情報を参照してください。

詳細

HTML DOM にアクセスするための MSHTML ライブラリに、createDocumentFromUrl というメソッドが有ります。

参照設定

このメソッドは Internet Explorer 5.5 から使用できます。

名前の通り、URL から HTMLDocument オブジェクトを取得する関数ですので、これを使ってみましょう。

その前に

本トピックは公開後 5 年近くが経過(2008/12 現在)しました。

執筆当時の記述が現在も有効かどうか検証してみたところ、筆者環境下(Windows XP HE SP3 + IE6)において、実行時に以下のような警告が上がることを確認しました。

IE security dialog

[はい] を押下すると実行されますが、[いいえ] を押下すると処理は失敗します(ただしキャッシュに残っていると [いいえ] 押下後にキャッシュの方を読むようです)。

どうやら mshtml.dll のバージョンアップに伴って、セキュリティが強化されていたようです。

IE7 と IE8 は確認していませんが(個人的に使う気がないので)、セキュリティの流れ的に、これより厳しくこそなれ、甘いということはなさそうな気がします。

とりあえず Internet Explorer の [ツール]-[インターネット オプション]-[セキュリティ] タブから接続先サイトを [信頼済みサイト] に登録しておけば、警告が回避できることは確認しました。

IE option dialog

しかし、接続先が不定の場合はあらかじめ信頼済みサイトに登録するのにも限度がありますから、ダイアログを完全には抑止しきれないでしょう(インターネット ゾーンのセキュリティを「低」にすれば警告は上がりませんが、これは激しく非推奨)。

また筆者は未確認ながら、Windows Vista では信頼済みサイトに登録してもメッセージを抑止できないという話もあります。

残念ながら、これでは本トピックの応用範囲が著しく狭まってしまうと言わざるをえません。

検索したところ、回避方法を見つけましたが、これには副作用があります。

[インターネット オプション] の設定にかかわらず警告なしで実行できる代わりに、スクリプトが実行されません。おそらくアクティブ コンテンツ全般が無効化されているものと思われます。

たとえば本サイトの各ページにはヘッダーとフッターがあり、リンクがいくつか含まれていますが、これらは JavaScript で動的に出力されています。先の回避方法を使ってリンクを列挙してみたところ、HTML ソースに直接記述されているリンクは取得されましたが、JavaScript で動的に出力しているリンクは抽出できませんでした。用途によってはほとんど問題ないか、むしろその方が好都合という場合もじゅうぶんありえますが、動的コンテンツを取得するのが目的の場合には逆に DOM を取得する意味がなくなってしまうかもしれません。

以下で紹介するコードは、セキュリティ アラート対策を施した改訂版になりますが、必要に応じて警告抑止オプションを指定するようにしてください。

簡単にコードの説明をしておきます。

createDocumentFromUrl メソッドによって新しい HTMLDocument オブジェクトを作成するには、親オブジェクト(HTMLDocument)が必要になります。

この引数 oHTML はその親オブジェクト用です。

要らないような気がするかもしれませんが、親オブジェクトを解放してしまうと肝腎の子オブジェクトも解放されてしまうので、引数は親子セットでお願いします。

documentElement.outerHTML で、Web ページの HTML ソースを取得できます。

で、何でそのバイト数が定数 EMPTY_DOC_LENB = 82 だったら空文書ということになるのかというと、たとえば実在しないイントラ文書をロードしようとした場合に表示される空文書の HTML ソースは、こうなります。

全部で 41 文字です。

文字列長の判定で最速なのはバイト操作系の LenB ですから、41 文字= 82 バイトで、空文書と判定できるという理屈になります。

もっとも .NET を見据えてバイト操作系関数を使用しないという場合は、もちろん Len 関数で 41 文字かどうか調べる方法でも構いません。

createDocumentFromUrl メソッドの第 1 引数 bstrUrl は言うまでも無く URL を示す文字列です。

では第 2 引数 bstrOptions は何かと言うと、私が調べた限りではどうやら HTMLDocument オブジェクトのスタイルシートに適用されるメディア タイプを指定するようです。

本来であれば印刷プレビュー用の場合に "print" を指定したりするのでしょうが、そういうケースはまず有り得ないと判断して、ここでは一律固定で vbNullString を渡して無効にしています。

では、この辺で使用例を見てみることにしましょう。

上記サンプルコードは当サイトの Top ページに存在する全リンクの一覧を出力します。

実行結果はイミディエイト ウィンドウに表示されます。

結果イメージは以下の通りです。

イミディエイト

オフライン中で、インターネットに接続していない場合でも、キャッシュにさえ残っていれば情報を取得することが出来ます。

もっとも、これは有り難い話ばかりとも限りません。リアルタイムの株価情報を取得する必要が有るようなケースでは、数時間前のキャッシュで有っても情報としての鮮度が致命的に失われる可能性があるので、注意が必要でしょう。

Web ページをダウンロードする方法〜 MSXML 編〜で紹介している XMLHTTP オブジェクトとの最大の違いは、こちらは JavaScript などのスクリプトを実行する(ただしセキュリティ警告を抑止しない場合、あるいは信頼済みサイトに登録する場合に限る)点です。

この違いによって、スクリプトによって生成されるコンテンツの結果にアクセスすることが出来ます。

XMLHTTP オブジェクトで Web ページを取得した場合、スクリプト ソース自体は取得できますが、スクリプトの実行結果は取得できませんし、もしスクリプトが外部ファイル参照になっていた場合は完全に欠落してしまいます。

もっとも取得したいデータがスクリプトに依存しない場合は、むしろその方が好都合な場合もじゅうぶん有り得る訳で、これはどちらが良い悪いという話ではなく、適材適所で使い分けを行なうべきものでしょう。

なおコードの実行に必要な mshtml.dll および mshtml.tlb は通常 OS や Internet Explorer に付属しているため、よほど特殊な環境でもない限り、何かのセットアップの必要はまず有りません。

もし IE 5.5 未満であるなどの理由で、必要なライブラリが見当たらない場合は、下記から最新の Internet Explorer をダウンロード/インストールすればよいでしょう。

IE ダウンロード

補足

かつて、Web ページを表示する際にユーザー ID とパスワードの入力を促すプロンプトが上がるような、アクセス制限が設定されているケースでは、URL に認証情報を附加する次のような方法によってプロンプトを抑止することが出来ました。

http://ユーザー ID:パスワード@www.f3.dion.ne.jp/~element/msaccess/

上記は URL 文字列に認証情報がそのまま埋め込まれてしまうため、セキュリティの観点からは推奨できませんが、簡便さから一般的によく利用されていた方法で、現在でも Web 上のリソースではこの方法を使ったサンプルコードが散見されます。

しかし Internet Explorer のセキュリティパッチを適用すると、この方法は使えなくなります。そのため現在では、ほとんどの環境でこの方法を使用できなくなりました。

詳細は下記を参照してください。

834489 - Internet Explorer で HTTP URL と HTTPS URL のユーザー情報を処理する際のデフォルトの動作を変更するソフトウェア アップデートのリリースについて

関連情報

WinHTTP ライブラリで Web スクレイピング(1)〜 GET 編〜

WinHTTP ライブラリで Web スクレイピング(2)〜 POST 編〜

WinHTTP ライブラリで Web スクレイピング(3)〜解析編〜

Web ページをダウンロードする方法〜 MSHTML 編〜

なお本トピックおよび上記トピックは、いずれも Web ページをオンメモリにロードする方法です。

メモリ上で操作/処理を行なう必要が無く、単にローカルファイルとして保存したいだけの場合は、URLMON API の URLDownloadToFile 関数を使用できます。

URLDownloadToFile 関数の Microsoft 社による使用例については、下記を参照してください。

244757 - How To Download a File Without Prompting機械翻訳

Web Team Talking: 大激震 > 最新の GIF の保存

また URLDownloadToFile 関数を VBA から使用する例として、おそらく最良の解説は、下記で参照することができます。

URLDownloadToFile APIを使用してダウンロードしてみた

ローカル キャッシュが取得されてしまう場合は、DeleteUrlCacheEntry 関数で事前にキャッシュを削除することで、最新の HTML ソースを取得することが出来ます。

インターネット一時ファイルの削除

262110 - How To Clear Cache When Your Application Hosts a WebBrowser Control機械翻訳

さらに高度な HTTP アクセスを行いたい場合は、下記を参照してください。

miyabi's Homepage - Technic - HTTPやFTPを使用してファイルのダウンロードする方法。

Happy! Happy! Island - Access VBA Tips+α - 番外編1.HTTPやFTPを使うには

VBAでファイルをダウンロードする:CodeZine

VB6 UniSock: winsock replacement - VBForums

WinInetによるHTTPデータの受信

上記により、大容量のファイルを転送する際にプログレスバーを表示するなどの対応が可能になります。

更新履歴