みなさん、こんにちは!タカハシ(@ntakahashi0505)です。
初心者向けエクセルVBAでIEを操作するシリーズの第4回目です。
前回はこちらの記事で
エラーを発生させずにHTMLドキュメントを取得するためにブラウザの読み込み待ち処理を入れる方法をお伝えしました。
今回からいよいよ開いたページに対して色々な操作をしていきたいと思います。
まず手始めに、Linksという命令とFor Each~Nextという繰り返し処理を用いてページ内のリンク先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
「いつも隣にITのお仕事」トップページからHTMLドキュメントを取得して、そのページタイトルを表示するという内容です。
ブラウザの読み込みが完了する前にHTMLドキュメントを取得しようとするとエラーになってしまうので、Do While~Loopで読み込み待ちの処理を入れております。
ページタイトルは単純にhtmlDoc.Titleで取得することができましたが、今回はこのページ内のリンク先URLをゴソっと取得していきたいと思います。
HTMLのアンカータグの仕組み
まずVBAでリンク先URLを取得するに先立って、リンク先URLがHTMLではどのように表現されているかを知っておく必要があります。
サイト上での表現は
こんな感じですね。これが実際にHTMLではどのように記述されているかと言いますと
いつも隣にITのお仕事
こんな風になっています。
リンクについては「<a>~</a>」と記述されるタグを使いまして、アンカータグと言います。通称aタグですね。
「href="~"」の部分はhref属性と言いまして、実際のリンク先のURLをこのダブルクォーテーションで囲っています。
ですから、このhref属性の値を取得するというのが今回のお題の最終目的となります。
Linksプロパティでa要素をコレクションとして取得
ページタイトルは1つのページ(つまりHTMLドキュメント)に対して1つしかありませんので、htmlDoc.Titleとすれば簡単に取得することができました。
しかし、リンク先URLは1つのページに1つしかないということはほとんどありません。JR東日本さんのトップページもたくさんのリンクがあります。
ですがエクセルVBAではオブジェクトをゴソっと集合として取り扱うことができる「コレクション」という概念があります。
任意のページのa要素をコレクションとして取得する場合は、HTMLDocumentオブジェクトのLinksプロパティを使います。
と書きます。
便利ですね~。
コレクションに含まれる全てのa要素からhref属性の値を取り出す
Linksプロパティでa要素のコレクションを取得できたら、次はそのコレクションに含まれる全てのa要素からhref属性の値を取り出す作業をします。
コレクションに含まれる全ての要素について何かをしたい場合はFor Each~Nextを使えばOKです。
まず繰り返しの際に都度要素を格納するオブジェクト変数を用意します。
今回、格納するのはa要素ですから、HTMLAnchorElementとしました。
繰り返しは以下のFor Each~Next文を使います。
'処理
Next オブジェクト変数
今回の場合はa要素のコレクションはhtmlDoc.Linksで取得できますから
Dim anchor As HTMLAnchorElement
For Each anchor In htmlDoc.Links
'処理
Next anchor
となります。
さらに、a要素からhref属性の値を取得する場合は、hrefプロパティを使います。
HTMLドキュメントが全部を含んでいて大きな器になっていて、その中に色々なものが入れ子構造で含まれていますので、欲しいものを次々に取得していくというのが、WEBスクレイピングの基本の進め方になります。
マトリョーシカみたいな感じです。なんとなくノリは理解できますかね?
今回はhrefをDebug.Printでイミディエイトウィンドウに出力したいと思います。
では以上を踏まえてプログラム全文です。
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
Dim anchor As HTMLAnchorElement
For Each anchor In htmlDoc.Links
Debug.Print anchor.href
Next anchor
End Sub
実行をしますと
まとめ
HTMLドキュメントからそのページのa要素を全て取得して、そのリンク先URLつまりhref属性の値を出力することができました。
またFor Each~Nextでコレクション内の要素全てについて繰り返す記述方法も理解していただけたと思います。
HTMLドキュメントを取り扱う場合は、コレクションはかなり使いますので、使い方に慣れていっていただければと思います。
次回はHTMLドキュメントからmetaタグのディスクリプションを取得する方法をお伝えしています。
SEO好きにはたまりませんね…!
連載目次:エクセル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属性を利用して画像ボタンをクリックする
コメント
楽しく読ませていただいております。
LINKSでURLが全部出てくることがわかりました。
特定のリンクアドレスのみ出力するにはどうしたら良いでしょうか?
例えば
abc.com/123/1.html
abc.com/123/2.html
abc.com/123/・・・・.html
abc.com/123/10000.html
のようなabc.com/123/にリンクするアドレスのみ取り出したい場合などはどうしたら良いでしょうか?
takaさん
コメントありがとうございます。
「abc.com/123/」を含むという条件式で取り出せば良いということですよね。Like演算子を使ったIf文で
とすればよいかと思います。
タカハシ様
VBA初心者の横山と申します。
楽しい記事をありがとうございます。
分かりやすく丁寧な解説でとても役に立っています。
さて、貴方様の本記事の最終のプログラム全文をコピーしてテストしたら、
16行目の下記の命令で,
「型が一致していない」のエラーが発生します。
解決策のご指導を頂けたら嬉しいです。
なお、私のPC環境は、 Win7+Excel2007 です。
(エラー発生行のコード)
16 Set htmlDoc = objIE.document ‘objIEで読み込まれているHTMLドキュメントをセット
★この記事に先だって、ツール>参照設定>を実施済みで現状を確認したら以下のライブラリにチェックがありました。
1)Visual Basic For Applications
2)Microsoft Excel12.0 Object Library
3)OLE Automation
4)Microsoft HTML Object Library
5)Miacrosoft Intenet Controls
以上です.
横山 登さん
コメントありがとうございます。
私の環境で再度確認しましたが、特に問題なく動作しているようです。
型が一致していないということなので、15行目に原因がある可能性が高いと思うのですが、いかがでしょうか?
タカハシ様
お世話になります。別コメントで質問を送信した横山です。
迅速なお返事に感謝します。
その後、自分で下記の調査をしましたので、参考として送ります。
お返事の作成に参考になればとしてお報せします。
(追加情報)
先の質問で社、16行目で「型が一致死ない」のエラーが出たので、
イミディアトウインドウで ?Typenama で変数の型を調べたら、
?typename(objIE.documen)…>HTMLDocument
?typename(htmlDoc)…>Nothing
となり、確かに型が一致していません。
一方、テストッコードの15行目には、
15 Dim htmlDoc As HTMLDocument ‘HTMLドキュメントオブジェクトを準備
と有るので、この型宣言分が無視されています。
以上ですが、、、
タカハシ様
お世話になります。別コメントで質問した横山です。
タカハシ様のテストではOKとの事なので、自分環境特有の問題と推察して、
自分努力により以下の手順により解決できたので報告します。
(解決できた手順)
1)VBE画面>ツール>オプション>”□変数の宣言を強制する。” のチェックを外す。(テストマクロには、Option Explicit 宣言を入れない)
2)15行目の先頭に”‘”を入れて jtmlDoc の型宣言文を無視させる。
3)実行すると、”?typename(htmlDoc)>HTMLdocument となり、処理もOKでした。
★自分の推察ですが、16行目の set文によって、htmlDoc の型が、HTMLDocument にセットされたのではないでしょうか?
★なお、上記手順1)で、”□変数の宣言を強制する。” のチェックを入れて、2)で 15行目をコメントアウトしたままでも実行時にエラーになりませんでした。この為、このトラブルは自分環境特有の問題ではないかと吸いさるする次第です。なお、この状態で実行すると、やはり正常動作しました。
結論として、15行目の型宣言があるとNG,なければOKという事です。
すなわち、タカハシ様の想像どうり 15行目が問題でした。
タカハシ様
今回は、自分の問題で貴殿の貴重な時間を浪費させてしまい、ごめんなさいです。
今後もぜひ楽しい解説を期待しています。
なお、上記と同様趣旨の報告を送信していますが、正しく送信できたのか分からないので再入力・再送信しました、もしもダブっていたら帆面あさいです。
以上
以上