スクレイピング

YouTube VBA

【EXCEL VBA】 Excelで資産管理しよう!スクレイピングで投信基準価格を取得! Webサイトのデータを取得 MSXMLを解説します IEとMSXMLの速度比較 ディベロッパーツール使い方

WEBデータの取得方法

MSXMLとは…

Microsoftが作ったXML (Extensible Markup Language)
XML とは、データを構造化して記述するためのマークアップ言語
HTMLのように、タグを使ってデータの意味や構造を定義する

Excel VBAのMSXML(Microsoft XML)ライブラリは、XMLデータの操作やWebサービスとの通信を行うための強力なツールです。MSXMLライブラリを使用することで、Excelから直接インターネット上のリソースにアクセスし、XMLデータの読み書きや解析を行うことができます。

はじめてのpythonとエクセルVBA入門
Excel VBAのMSXML(Microsoft XML)ライブラリ:XMLデータの処理とWebサービスの活用
https://python-vba.com/excel-vba-msxmlmicrosoft-xml/#google_vignette

MSXMLを使うためにライブラリーの参照設定が必要です

MSXMLのオブジェクトを作成

Microsoft XML, v6.0を参照設定する

あるいは

参照設定を使わない場合…

URL情報をGET

リクエスト送信

読込に時間がかかるので、読み込み完了まで待機

ReadyState定数

ここまでは、すべて同じ

終了処理

HTMLの検証

WebページのHTML・CSSを確認

[右クリック] →[検証]

Elememtをクリック→参照したい箇所をクリック→対象HTMLがハイライトされる緑

調べたい要素を[右クリック] →[検証]→対象HTMLがハイライトされる

タイトル取得

ページの読み込みからの続き

HTML文字列からHTLMドキュメントを生成する

Microsoft HTML Object Libraryを参照設定する

まとめて、これでもOK!

HTMLオブジェクトに書き出し

書き出しは、innerTextではなく、innerHTMLです!
これを間違えて、30分ぐらい悩んでました°(°´ᯅ`°)°。

要素の取り出し

コレクション複数形に! getElementsです

オブジェクト・コレクション・Object変数については、こちらを見てね!
ForEachについても…

インデックス番号

インデックス番号から始まる
h1タグは、多分1つしかないので、1番目=インデックス番号0を指定する

データ取得プロパティと取得内容

Codeと指定するのは、
WorkSheets(“シート名”)とするのと同じ

シート名を変更しても、
プログラムの変更が不要です

要素の個数

h2は、インデックス番号0,1,2,3 の4つ

要素の取り出し

For Each要素を1つずつなくなるまでObject変数objに取り出す

繰り返し処理については、こちらを見てね!

終了処理

リストタグ

~HTMLオブジェクトに書き出しまでは同じ

親子関係

HTMLを見ると、家賃・管理費の上にliタグ、その上にulタグがある
ulタグ→子liタグ
親タグから探って行こう!

親ulタグの個数

ulタグの表示

改行を削除
Replace(“文字列”, 改行コード定数, “”)

どうやらul(5)に物件情報があるらしい!?
ul(5)の内容

子liタグの個数

たくさんあるulの中で欲しいのは、ul(5)だけ!
ul(5)だけをオブジェクト変数に取り出す

objElement ←ul(5)だけ

liタグの表示

objul(5)の中のliのひとつ

3件ごとに家賃と管理費があるね!
1件ずつ見て行こう!

objprice←li(0)

span・ddタグ

spanは1つだけなので、ForEachなしで、
objPrice.getElementsByTagName(“span”)(0).innerText
等としてもOK!

全件取得

3件ごとに要素の取り出し
インデックス番号を3でわった余りが、0のときだけ、

家賃と管理費を取り出す

i Mod 3 = 0

家賃と管理費すべて取得できた!

テーブル

検索

Ctrl+F→table

tr→td→div

trタグ

trの下にtdがあるので、次はtdを見てみよう!

tdタグ

1件分のテーブル情報が取り出せた!

divタグ

1件分の家賃と管理費を取り出せた!

親子孫関係

trの下にtdがあり、tdの下にdivがあり、入れ子になっています
親・子・孫の関係です

HTMLが入れ子の構造になっているので、
VBAでも同様に入れ子のForEach構造にして、一気に取得できます

全テーブル取得

Youtubeでは、3重のループにしていましたが、
一番外にtableのループも加えなければいけないのかもしれません!?
table加え4重のループにしました

・各オブジェクト変数

・4重のループ

赤枠1件(1テーブル)のデータ

ソースコード

Sub スクレイピングタイトル取得()
'MSXML版
    '
    '**設定**
    
    'MSXMLのオブジェクトを作成
    '参照設定 必要
    'Microsoft XML, v6.0
    
    'オブジェクトを作成し、変数にセットします
    Dim xmlHttp As MSXML2.XMLHTTP60
    Set xmlHttp = New MSXML2.XMLHTTP60
    'あるいは
    'Dim xmlHttp As New MSXML2.XMLHTTP60
    
    'あるいは、参照設定を使わない場合
    'Set xmlHttp = CreateObject("MSXML2.XMLHTTP.6.0")
         
    '**処理**

    '指定のURLをGET
    Dim url As String
    url = "https://                               "
    
    xmlHttp.Open "GET", url
      
    'リクエスト送信
    
    xmlHttp.send
    
     'ページの読み込みが完了するまで待つ (READYSTATE_COMPLETE:4)
     Do While xmlHttp.readyState <> 4     'READYSTATE_COMPLETE
        DoEvents
    Loop
    
    'HTML文字列からHTLMドキュメントを生成する
    '参照設定 必要
    'Microsoft HTML Object Library
     
    'HTMLドキュメント作成
  Dim objHtml As HTMLDocument
  Set objHtml = New HTMLDocument
    ’Dim objHtml As New HTMLDocument
     
     'レスポンスのテキストをHTMLオブジェクトに書き出し
    objHtml.body.innerHTML = xmlHttp.responseText
    'objHtml.write xmlHttp.responseText
  
   'h1タグの取り出し
    Dim title As String
    title = objHtml.getElementsByTagName("h1")(0).innerText
    
     'シートクリア
    Code.Cells.Clear
    
    'タイトル表示
    Code.Cells(1, 1) = "h1"
    Code.Cells(1, 2) = "0"
    Code.Cells(1, 3) = title
             
    'h2タグの個数
    MsgBox "h2 " & objHtml.getElementsByTagName("h2").Length
    
    'h2タグをObject変数に代入
    Dim i As Long, Gyo As Long
    i = 0: Gyo = 2
    Dim obj As Object
    For Each obj In objHtml.getElementsByTagName("h2")
       Code.Cells(Gyo, 1) = "h2"
       Code.Cells(Gyo, 2) = i
       Code.Cells(Gyo, 3) = obj.innerText
       Gyo = Gyo + 1
        i = i + 1
    Next obj
    
    'For Each→ForNext
    Set obj = objHtml.getElementsByTagName("h2")
    For i = 0 To obj.Length - 1
        Code.Cells(Gyo, 1) = "h2"
       Code.Cells(Gyo, 2) = i
       Code.Cells(Gyo, 3) = obj(i).innerText
       Gyo = Gyo + 1
    Next i
    
    '**終了処理**
    
    'オブジェクト解放
    Set xmlHttp = Nothing
    Set objHtml = Nothing
    Set obj = Nothing
    
End Sub
Sub スクレイピングul取得()
'MSXML版
    '
    '**設定**
    
    'MSXMLのオブジェクトを作成
    '参照設定 必要
    'Microsoft XML, v6.0
    Dim xmlHttp As MSXML2.XMLHTTP60
    Set xmlHttp = New MSXML2.XMLHTTP60
    'あるいは
    'Set xmlHttp = CreateObject("MSXML2.XMLHTTP.6.0")
         
    '**処理**

    '指定のURLを開く
    Dim url As String
    url = "https://    "
    xmlHttp.Open "GET", url
      
    'リクエスト送信
    xmlHttp.send
    
     'ページの読み込みが完了するまで待つ   (READYSTATE_COMPLETE:4)
    Do While xmlHttp.readyState <> 4     'READYSTATE_COMPLETE
        DoEvents
    Loop
    
    'HTML文字列からHTLMドキュメントを生成する
    '参照設定 必要
    'Microsoft HTML Object Library
     
    'HTMLドキュメントオブジェクト作成
    Dim objHtml As HTMLDocument
    Set objHtml = New HTMLDocument
     'Dim objHtml As New HTMLDocument
     
    'レスポンスのテキストをHTMLオブジェクトに書き出し
    objHtml.body.innerHTML = xmlHttp.responseText
    'objHtml.write xmlHttp.responseText
    
     'シートクリア
    Code.Cells.Clear
    Code.Cells(1, 1) = "コード"
    Code.Cells(1, 2) = "No."
    Code.Cells(1, 3) = "innerHTML"
    Code.Cells(1, 4) = "innerText"
    Code.Cells(1, 5) = "outerHTML"
 
        
    Dim i As Long, Gyo As Long, Retu As Long
    i = 0: Gyo = 2
     
    'ulタグの個数
    Debug.Print "ul " & objHtml.getElementsByTagName("ul").Length
    
    'ulタグの表示
    'レスポンステキストのulタグを1つずつObject変数に取り出す
    Dim obj As Object
    For Each obj In objHtml.getElementsByTagName("ul")
        Code.Cells(Gyo, 1) = "ul"
        Code.Cells(Gyo, 2) = i                          'インデックス番号
        Code.Cells(Gyo, 3) = Replace(obj.innerHTML, vbLf, "")
        Code.Cells(Gyo, 4) = Replace(obj.innerText, vbLf, "")
        Code.Cells(Gyo, 5) = Replace(obj.outerHTML, vbLf, "")
        Gyo = Gyo + 1
        i = i + 1
    Next obj
    
    'ul(5)の中に 物件情報がある
    Dim objElement As Object
    Set objElement = objHtml.getElementsByTagName("ul")(5)
    
    'ul(5)の中のliタグの個数
    Debug.Print "li " & objElement.getElementsByTagName("li").Length
    
    i = 0
    
    'liタグの表示
    For Each obj In objElement.getElementsByTagName("li")
        Code.Cells(Gyo, 1) = "li"
        Code.Cells(Gyo, 2) = i
        Code.Cells(Gyo, 3) = Replace(obj.innerHTML, vbLf, "")
        Code.Cells(Gyo, 4) = Replace(obj.innerText, vbLf, "")
        Code.Cells(Gyo, 5) = Replace(obj.outerHTML, vbLf, "")
        Gyo = Gyo + 1
        i = i + 1
    Next obj
 
    'objElementのli(0)をobjPriceに代入
    Dim objPrice As Object
    Set objPrice = objElement.getElementsByTagName("li")(0)
    
    'li(0)の中のspanタグの個数
    Debug.Print "span " & objPrice.getElementsByTagName("span").Length
        
    'spanタグの表示
    i = 0
    For Each obj In objPrice.getElementsByTagName("span")
        Code.Cells(Gyo, 1) = "span"
        Code.Cells(Gyo, 2) = i
        Code.Cells(Gyo, 3) = Replace(obj.innerHTML, vbLf, "")
        Code.Cells(Gyo, 4) = Replace(obj.innerText, vbLf, "")
        Code.Cells(Gyo, 5) = Replace(obj.outerHTML, vbLf, "")
        Gyo = Gyo + 1
        i = i + 1
    Next obj
    
    Debug.Print objPrice.getElementsByTagName("span")(0).innerText
        
    'li(0)の中のddタグの個数
    Debug.Print "dd " & objPrice.getElementsByTagName("dd").Length
    
    'ddタグの表示
    i = 0
    For Each obj In objPrice.getElementsByTagName("dd")
        Code.Cells(Gyo, 1) = "dd"
        Code.Cells(Gyo, 2) = i
        Code.Cells(Gyo, 3) = Replace(obj.innerHTML, vbLf, "")
        Code.Cells(Gyo, 4) = Replace(obj.innerText, vbLf, "")
        Code.Cells(Gyo, 5) = Replace(obj.outerHTML, vbLf, "")
        Gyo = Gyo + 1
        i = i + 1
    Next obj
    
    '**終了処理**
    'オブジェクト解放

    Set xmlHttp = Nothing
    Set objHtml = Nothing
    Set objElement = Nothing
    Set objPrice = Nothing
    Set obj = Nothing
    
End Sub
Sub スクレイピング家賃取得()
'MSXML版
    '
    '**設定**
    
    'MSXMLのオブジェクトを作成
    '参照設定 必要
    'Microsoft XML, v6.0
    Dim xmlHttp As MSXML2.XMLHTTP60
    Set xmlHttp = New MSXML2.XMLHTTP60
    'あるいは
    'Set xmlHttp = CreateObject("MSXML2.XMLHTTP.6.0")
         
    '**処理**

    '指定のURLを開く
    Dim url As String
    url = "https://  "
    xmlHttp.Open "GET", url
      
    'リクエスト送信
    xmlHttp.send
    
     'ページの読み込みが完了するまで待つ   (READYSTATE_COMPLETE:4)
    Do While xmlHttp.readyState <> 4     'READYSTATE_COMPLETE
        DoEvents
    Loop
    
    'HTML文字列からHTLMドキュメントを生成する
    '参照設定 必要
    'Microsoft HTML Object Library
     
    'HTMLドキュメントオブジェクト作成
    Dim objHtml As HTMLDocument
    Set objHtml = New HTMLDocument
     'Dim objHtml As New HTMLDocument
     
    'レスポンスのテキストをHTMLオブジェクトに書き出し
    objHtml.body.innerHTML = xmlHttp.responseText
    'objHtml.write xmlHttp.responseText
    
     'シートクリア
    Code.Cells.Clear
    Code.Cells(1, 1) = "コード"
    Code.Cells(1, 2) = "No."
    Code.Cells(1, 3) = "innerHTML"
    Code.Cells(1, 4) = "innerText"
    Code.Cells(1, 5) = "outerHTML"
        
    Dim i As Long, Gyo As Long, Retu As Long
    i = 0: Gyo = 2
     
    'ulタグの個数
    'Debug.Print objHtml.getElementsByTagName("ul").Length
    
    'ulタグの表示
    Dim obj As Object
    'レスポンステキストのulタグをObject変数に代入
    For Each obj In objHtml.getElementsByTagName("ul")
        Code.Cells(Gyo, 1) = "ul"
        Code.Cells(Gyo, 2) = i
        Code.Cells(Gyo, 3) = Replace(obj.innerHTML, vbLf, "")
        Code.Cells(Gyo, 4) = Replace(obj.innerText, vbLf, "")
        Code.Cells(Gyo, 5) = Replace(obj.outerHTML, vbLf, "")
        Gyo = Gyo + 1
        i = i + 1
    Next obj
    
    'ul(5)の中に 物件情報がある 
    Dim objElement As Object
    Set objElement = objHtml.getElementsByTagName("ul")(5)

    'ul(5)の中のliタグ
    'Debug.Print objElement.getElementsByTagName("li").Length
    
    i = 0
    'liタグの表示 "ul"5 li-0,3,6,9…
    For Each obj In objElement.getElementsByTagName("li")
       If i Mod 3 = 0 Then
            Code.Cells(Gyo, 1) = "span dd"
            Code.Cells(Gyo, 2) = i
            Code.Cells(Gyo, 3) = obj.getElementsByTagName("span")(0).innerText
            Code.Cells(Gyo, 4) = obj.getElementsByTagName("dd")(0).innerText
            Gyo = Gyo + 1
        End If
        i = i + 1
    Next obj
    
    '**終了処理**
    'オブジェクト解放

    Set xmlHttp = Nothing
    Set objHtml = Nothing
    Set objElement = Nothing
    Set obj = Nothing
    
End Sub
Sub スクレイピングtable取得()
'MSXML版
    '
    '**設定**
    
    'MSXMLのオブジェクトを作成
    '参照設定 必要
    'Microsoft XML, v6.0
    Dim xmlHttp As MSXML2.XMLHTTP60
    Set xmlHttp = New MSXML2.XMLHTTP60
    'あるいは
    'Set xmlHttp = CreateObject("MSXML2.XMLHTTP.6.0")
         
    '**処理**

    '指定のURLを開く
    Dim url As String
    url = "https://    "
    xmlHttp.Open "GET", url
      
    'リクエスト送信
    xmlHttp.send
    
     'ページの読み込みが完了するまで待つ   (READYSTATE_COMPLETE:4)
    Do While xmlHttp.readyState <> 4     'READYSTATE_COMPLETE
        DoEvents
    Loop
    
    'HTML文字列からHTLMドキュメントを生成する
    '参照設定 必要
    'Microsoft HTML Object Library
     
    'HTMLドキュメントオブジェクト作成
    Dim objHtml As HTMLDocument
    Set objHtml = New HTMLDocument
     'Dim objHtml As New HTMLDocument
     
    'レスポンスのテキストをHTMLオブジェクトに書き出し
    objHtml.body.innerHTML = xmlHttp.responseText
    'objHtml.write xmlHttp.responseText
    
     'シートクリア & 見出し
    Code.Cells.Clear
    Code.Cells(1, 1) = "コード"
    Code.Cells(1, 2) = "No."
    Code.Cells(1, 3) = "innerHTML"
    Code.Cells(1, 4) = "innerText"
    Code.Cells(1, 5) = "outerHTML"
    
    Dim i As Long, Gyo As Long, Retu As Long
     i = 0: Gyo = 2
     
    'trタグの個数
    Dim obj As Object
    Debug.Print "tr " & objHtml.getElementsByTagName("tr").Length
    
    'trタグの表示
    For Each obj In objHtml.getElementsByTagName("tr")
        Code.Cells(Gyo, 1) = "tr"
        Code.Cells(Gyo, 2) = i
        Code.Cells(Gyo, 3) = Replace(obj.innerHTML, vbLf, "")
        Code.Cells(Gyo, 4) = Replace(obj.innerText, vbLf, "")
        Code.Cells(Gyo, 5) = Replace(obj.outerHTML, vbLf, "")
        Gyo = Gyo + 1
        i = i + 1
    Next
    
    'trタグをObject変数に代入
    Dim objElement As Object
    Set objElement = objHtml.getElementsByTagName("tr")(0)
    'tdタグの個数
    Debug.Print "td " & objElement.getElementsByTagName("td").Length
    
    'tdタグの表示
    i = 0
    For Each obj In objElement.getElementsByTagName("td")
        Code.Cells(Gyo, 1) = "td"
        Code.Cells(Gyo, 2) = i
        Code.Cells(Gyo, 3) = Replace(obj.innerHTML, vbLf, "")
        Code.Cells(Gyo, 4) = Replace(obj.innerText, vbLf, "")
        Code.Cells(Gyo, 5) = Replace(obj.outerHTML, vbLf, "")
        Gyo = Gyo + 1
        i = i + 1
    Next
    
    'td(0)をObject変数に代入
    Dim objdiv As Object
    Set objdiv = objElement.getElementsByTagName("td")(0)

    'divタグの個数
    Debug.Print "div " & objdiv.getElementsByTagName("div").Length
    
    'divタグの表示
    i = 0
    For Each obj In objdiv.getElementsByTagName("div")
        Code.Cells(Gyo, 1) = "div"
        Code.Cells(Gyo, 2) = i
        Code.Cells(Gyo, 3) = Replace(obj.innerHTML, vbLf, "")
        Code.Cells(Gyo, 4) = Replace(obj.innerText, vbLf, "")
        Code.Cells(Gyo, 5) = Replace(obj.outerHTML, vbLf, "")
        Gyo = Gyo + 1
        i = i + 1
    Next
    
    '**終了処理**
    'オブジェクト解放

    Set xmlHttp = Nothing
    Set objHtml = Nothing
    Set objElement = Nothing
  Set objdiv = Nothing
    Set obj = Nothing
    
End Sub
Sub スクレイピング全table取得()
'MSXML版
    '
    '**設定**
    
    'MSXMLのオブジェクトを作成
    '参照設定 必要
    'Microsoft XML, v6.0
    Dim xmlHttp As MSXML2.XMLHTTP60
    Set xmlHttp = New MSXML2.XMLHTTP60
    'あるいは
    'Set xmlHttp = CreateObject("MSXML2.XMLHTTP.6.0")
         
    '**処理**

    '指定のURLを開く
    Dim url As String
    url = "https://  "
    xmlHttp.Open "GET", url
      
    'リクエスト送信
    xmlHttp.send
    
     'ページの読み込みが完了するまで待つ   (READYSTATE_COMPLETE:4)
    Do While xmlHttp.readyState <> 4     'READYSTATE_COMPLETE
        DoEvents
    Loop
    
    'HTML文字列からHTLMドキュメントを生成する
    '参照設定 必要
    'Microsoft HTML Object Library
     
    'HTMLドキュメントオブジェクト作成
    Dim objHtml As HTMLDocument
    Set objHtml = New HTMLDocument
     'Dim objHtml As New HTMLDocument
     
    'レスポンスのテキストをHTMLオブジェクトに書き出し
    objHtml.body.innerHTML = xmlHttp.responseText
    'objHtml.write xmlHttp.responseText
    
     'シートクリア & 見出し
    Code.Cells.Clear
    Code.Cells(1, 1) = "コード"
    Code.Cells(1, 2) = "No."
    Code.Cells(1, 3) = "innerHTML"
    Code.Cells(1, 4) = "innerText"
    Code.Cells(1, 5) = "outerHTML"
    
    
    Dim objtable As Object   'tableのObject変数
    Dim objtr As Object        'trのObject変数
    Dim objtd As Object       'tdのObject変数
    Dim objdiv As Object      'divのObject変数
    
    Dim i As Long, Gyo As Long
     i = 1: Gyo = 2
        
    'tableの表示
    For Each objtable In objHtml.getElementsByTagName("table")
   
        For Each objtr In objtable.getElementsByTagName("tr")
            
            For Each objtd In objtr.getElementsByTagName("td")
                
                For Each objdiv In objtd.getElementsByTagName("div")
                
                    Code.Cells(Gyo, 1) = "table tr td div"
                    Code.Cells(Gyo, 2) = i
                    Code.Cells(Gyo, 3) = Replace(objdiv.innerHTML, vbLf, "")
                    Code.Cells(Gyo, 4) = Replace(objdiv.innerText, vbLf, "")
                    Code.Cells(Gyo, 5) = Replace(objdiv.outerHTML, vbLf, "")
                    Gyo = Gyo + 1
                   
                Next objdiv
                
            Next objtd
             
        Next objtr
        i = i + 1        'テーブルの数
    Next objtable
    
    '**終了処理**
    'オブジェクト解放

    Set xmlHttp = Nothing
    Set objHtml = Nothing
    Set objtable = Nothing
    Set objtr = Nothing
    Set objtd = Nothing
    Set objdiv = Nothing
    
End Sub

コメント