Help us understand the problem. What is going on with this article?

[VBA]30分あればできるVBAスクレイピング

More than 1 year has passed since last update.

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する度に使うので書いて書いおくと楽チンです。

WaitResponse()
Sub WaitResponse(objIE As Object)
    Do While objIE.Busy = True Or objIE.readyState < READYSTATE_COMPLETE '読み込み待ち
        DoEvents
    Loop
End Sub

結果
image.png

2.3 データの特定

④HTMLからタグ名や、クラス、id名を検索条件として欲しい値の場所を特定する

まず欲しいデータがHTMLのどこにあるのか特定しなければなりません。
場所を特定する際の情報としては以下が挙げられます。

特定の情報 使用するメソッド
タグ名 <span ,<form,<p
クラス名 各タグに記載されるclass="class_sample"のこと
id名 各タグに記載されるid="id_sample"のこと

他にもありますが一旦ここまで。
上記を踏まえて、今回取得したい値のタグを見てみましょう。

ここではChromeのデベロッパーツールを使います。
F12を押せば開きます。

今回はフッターに記載されているライセンスの記述文字を取得します。

image.png

    Dim htmlDoc As HTMLDocument 'HTMLドキュメントオブジェクトを準備
    Set htmlDoc = objIE.document 'objIEで読み込まれているHTMLドキュメントをセット

    '---------------------------------
    '  footerの文字を取得
    '  今回はクラスを指定(getElementsByClassNameで)してタグを特定します
    '  (0)は「class="license"」がついてるタグの一つ目を指します
    '---------------------------------
    MsgBox htmlDoc.getElementsByClassName("license")(0).innerHTML

結果
image.png

今回は指定した「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の方がよい

test
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

SoreKiita
やたらめったら書きます。 好奇心で動きます。
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away