#0 前置き
昨今、様々な言語でスクレイピングが出来ますが、VBAなら開発環境構築が不要でサイトから引っ張ってきた値をCsvに出す必要もなく直接セルに設定できるのは中々魅力的だと個人的に思います。
作成したマクロはダウンロードできるのでよかったらどうぞ
#1 事前準備
##1.1 必要な環境
・Excel
・Internet Explore
※バージョンについては知らない
これだけでスクレイピングができる環境が整います。他の言語に比べるとかなりお手軽だと思いません?
##1.2 ライブラリの追加
標準のライブラリだとDOM操作、およびスクレイピングはできないのでライブラリを追加します。
①Excelを開いたらVBEを開く(Alt+F11)
②メニューバー→「ツール」→「参照設定」
③ずらずらとライブラリが並んでいるが、
その中から以下の二つを探してチェックを入れる。
・Microsoft HTML Object Library
・Microsoft Internet Controls
チェックを入れたら「OK」ボタンを押す。
これで追加完了。
この2つを入れることではIEの操作、HTMLの操作ができるようになります。
#2 実際にスクレイピング
##2.1スクレイピング処理の流れ
①IEオブジェクトを作成
②IEオブジェクト.navigateでサイトにアクセス
③読み込み待ちをする(navigateする度に必要)
④HTMLからタグ名や、クラス、id名を検索条件として欲しい値の場所を特定する
##2.2 IEでサイトにアクセスする例
①IEオブジェクトを作成
②IEオブジェクト.navigateでサイトにアクセス
③読み込み待ちをする(navigateする度に必要)
今回はサンプルとして「ゴールドポイントカード」のサイトにアクセスします。
Sub testIE()
Dim objIE As InternetExplorer 'IEオブジェクトを準備
Set objIE = CreateObject("Internetexplorer.Application") '新しいIEオブジェクトを作成してセット
objIE.Visible = True 'IEを表示
objIE.navigate "https://secure.goldpoint.co.jp/gpm/authentication/index.html" 'IEでURLを開く
Call WaitResponse(objIE) '読み込み待ち
End Sub
下記のSubはnavigateする度に使うので書いて書いおくと楽チンです。
Sub WaitResponse(objIE As Object)
Do While objIE.Busy = True Or objIE.readyState < READYSTATE_COMPLETE '読み込み待ち
DoEvents
Loop
End Sub
##2.3 データの特定
④HTMLからタグ名や、クラス、id名を検索条件として欲しい値の場所を特定する
まず欲しいデータがHTMLのどこにあるのか特定しなければなりません。
場所を特定する際の情報としては以下が挙げられます。
特定の情報 | 使用するメソッド |
---|---|
タグ名 | <span ,<form,<p |
クラス名 | 各タグに記載されるclass="class_sample"のこと |
id名 | 各タグに記載されるid="id_sample"のこと |
他にもありますが一旦ここまで。
上記を踏まえて、今回取得したい値のタグを見てみましょう。
ここではChromeのデベロッパーツール
を使います。
F12
を押せば開きます。
今回はフッターに記載されているライセンスの記述文字を取得します。
Dim htmlDoc As HTMLDocument 'HTMLドキュメントオブジェクトを準備
Set htmlDoc = objIE.document 'objIEで読み込まれているHTMLドキュメントをセット
'---------------------------------
' footerの文字を取得
' 今回はクラスを指定(getElementsByClassNameで)してタグを特定します
' (0)は「class="license"」がついてるタグの一つ目を指します
'---------------------------------
MsgBox htmlDoc.getElementsByClassName("license")(0).innerHTML
今回は指定した「class="license"」は一つのタグでしか使われていませんでしたが、
もし複数あってHTMLの上から数えて2つ目のタグの値が欲しい場合は、
MsgBox htmlDoc.getElementsByClassName("license")(1).innerHTML
全てのタグを取得したい場合は以下のようにします
'---------------------------------
'添え字を指定せず存在するだけループさせれば全て取得できます
'---------------------------------
For Each str In htmlDoc.getElementsByClassName ("license")
Debug.Print "出力:" & str
Next str
#3 その他サンプル
これは随時更新していく予定です。
##3.1 idの場合
'idの場合は必ず一つしかないため添え字は不要です
htmlDoc.getElementById ("id").innerHTML
##3.2 他getElemen
htmlDoc.getElementsByName 'コレクションを返す
htmlDoc.getElementsByClassName 'コレクションを返す
htmlDoc.getElementsByTagName 'コレクションを返す
htmlDoc.getElementsByTagNameNS 'コレクションを返す
##3.3 メソッド
htmlDoc.Links 'ドキュメント内のリンクすべて取得
htmlDoc.getElementById("").Click
htmlDoc.getElementById("").className
htmlDoc.getElementById("").innerHTML
htmlDoc.getElementById("").innerText
htmlDoc.getElementById("").outerHTML
htmlDoc.getElementById("").outerText
htmlDoc.getElementById("").contains
##3.4 formのテキストエリアに値を設定
objIE.document.forms("form").Item("ここにid").Value = "huga"
objIE.document.forms("form").Item("ここにid").Value = "foo"
##3.5 javascript実行
objIE.navigate "JavaScript:methodName"
#4.データ操作
これらを必ず使え!というわけではなく、使ったら便利なのと良く忘れるので書いておきます。
##4.1 Dictionary
ハッシュ(連想配列)として使う。
Collectionでも同じことができるが処理速度と便利なメソッドがある点においてDictionaryの方がよい
Sub test()
'宣言と初期化
Dim obj As Object
Set obj = CreateObject("Scripting.Dictionary")
' キーと値の設定
obj.Add "foo", 100
obj.Add "bar", 200
obj.Add "hoge", 300
' 値の取得
Dim key As Variant
For Each key In obj
MsgBox obj(key)
Next key
'または
hash("foo") '->100
Set obj = Nothing
End Sub
メソッド名 | 説明 |
---|---|
Add(key,item) | キーと値のセットを追加 |
Exists(key) | 指定されたキー(key)の存在 |
Item(key) | キー(key)に紐づく値 |
##4.2 Collection
基本的にDictionaryと同じ感覚
ただ動作が顕著に遅いことがある。
沢山オブジェクトを作るとそうなる。
'----------------
'宣言と初期化
'----------------
Dim collec As Collection
Set collec = New Collection
'----------------
'値追加
'----------------
''keyと値のセット
collec.Add "キー","値"
''値のみ
collec.Add "値"
'※値の型にバラツキがあっても問題ない
'→String,配列,integerが混ざっててもおけ
'----------------
'値の取り出し
'----------------
''keyを指定して取り出し
cllec("キー") '→値
''拡張forで取り出し
For each value In collec
Debug.print value
Next value