【Excel VBA】ヤフーファイナンス時価総額ランキングの自動取得(Excelシートに書き出し)(「HTTP通信」のみ)

VBA

2022年7月2日現在のWebサイトでスクレイピングしています。今後サイトの仕様に変更があった場合は、下記のコードではスクレイピングできない場合があります>

「Excel VBA」で、IEやSeleniumBasicを使わずに、「HTTP通信」のみで、ヤフーファイナンスの時価総額ランキングをすべてExcelシートに書き出すコードです。

「HTTP通信」では、サイトの次ページを読み込む際に、ユーザのリアル操作が必要となりますので、意図的に空のユーザーフォーム(UserForm1)を開閉しています。

(書き出すExcelシートには、予めヘッダーや書式等を設定しておきます)

Sub ヤフーファイナンス情報取得_spot_HTTP()

    Const SHOWCNT As Integer = 50
    
    On Error Resume Next
    
    Dim httpreq As Variant
    Set httpreq = CreateObject("MSXML2.XMLHTTP")
    
    httpreq.Open "GET", "https://finance.yahoo.co.jp/stocks/ranking/marketCapitalHigh?market=all&term=daily"
    httpreq.send
    
    Do While httpreq.readyState < 4
        DoEvents
    Loop
    
    Dim html As Variant
    Set html = CreateObject("htmlfile")
    html.write httpreq.responseText
    
  '以下で開いたユーザーフォームが1秒後に閉じる
    Application.OnTime Now() + TimeSerial(0, 0, 1), "CloseUserForm"
    UserForm1.Show
    
    Dim strCntCss As String
    strCntCss = "#root > main > div > div.rMa89KwT._34OEfNCy._2STjqM5M > div.XuqDlHPN > section > div > div._3G6OUGtH > div > div > p:nth-child(1)"

    'トータル件数を取得
    Dim strCnt As String
    strCnt = html.querySelector(strCntCss).innerText
    strCnt = Mid(strCnt, InStr(strCnt, "/") + 2, 4) * 1
    
    '繰り返し回数を計算
    Dim maxCnt As Integer
    maxCnt = strCnt / SHOWCNT
    
    With ThisWorkbook.Worksheets("HTTP") '情報を書き出すシート名を「HTTP」とする
    
        Dim clrMaxRow As Integer
        Dim clrMaxClmn As Integer
        clrMaxRow = .Cells(.Rows.Count, 2).End(xlUp).Row
        clrMaxClmn = .Cells(2, .Columns.Count).End(xlToLeft).Column
        .Range(.Cells(2, 2), .Cells(clrMaxRow, clrMaxClmn)).ClearContents
        
        Dim starttime As Date   '処理の開始時刻を格納
        starttime = Time
        
        Dim i As Integer
        Dim j As Integer
        Dim x As Integer
        j = 1
        x = 1
        
        For i = 1 To maxCnt            
            Dim trs As Object
            Dim tr As Object
            Dim tds As Object
            Dim td As Object
            Set trs = html.getElementsByTagName("tr")
            For Each tr In trs
                Dim k As Integer
                Dim m As Integer
                k = 1
                m = 0
                .Cells(j, k) = tr.getElementByTagname("th").innerText
                k = k + 1
                Dim strTexts As Variant
                Dim strText As Variant
                Set tds = tr.getElementsByTagName("td")
                For Each td In tds                    
                    Select Case k
                        Case 2
                            Dim l As Integer
                            l = 0
                            strTexts = Split(td.innerText, vbLf)
                            For Each strText In strTexts
                                If l = 0 Then
                                    .Cells(j, k + l + m) = Left(strText, Len(strText) - 5)
                                    l = l + 1
                                    .Cells(j, k + l + m) = Right(strText, 5) * 1
                                    l = l + 1
                                Else
                                    .Cells(j, k + l + m) = strText
                                    l = l + 1
                                End If
                            Next strText
                            m = m + l - 1
                        Case 3
                            l = 0
                            strTexts = Split(td.innerText, vbLf)
                            For Each strText In strTexts
                                If l = 1 Then
                                    .Cells(j, k + l + m) = strText * 1
                                Else
                                    .Cells(j, k + l + m) = strText
                                End If
                                l = l + 1
                            Next strText
                            m = m + l - 1
                        Case 4
                            .Cells(j, k + m) = _
                               Left(td.innerText, InStr(td.innerText, "株") - 1) * 1
                        Case 5
                            .Cells(j, k + m) = _
                               Left(td.innerText, InStr(td.innerText, "百") - 1) * 1
                        Case Else
                             l = 0
                            strTexts = Split(td.innerText, vbLf)
                            For Each strText In strTexts
                                .Cells(j, k + l + m) = strText * 1
                                l = l + 1
                            Next strText
                    End Select
                    k = k + 1
                Next td
                Set tds = Nothing
                j = j + 1
            Next tr
            
            Set trs = Nothing
            Set html = Nothing
            Set httpreq = Nothing
            
            x = x + 1
            Set httpreq = CreateObject("MSXML2.XMLHTTP")
            httpreq.Open "GET",  _  
                "https://finance.yahoo.co.jp/stocks/ranking/marketCapitalHigh?" & _
                "market=all&term=daily&page=" & x
            httpreq.send
    
            Do While httpreq.readyState < 4
                DoEvents
            Loop
    
            Set html = CreateObject("htmlfile")    
            html.write httpreq.responseText
            
            '以下で開いたユーザーフォームが1秒後に閉じる _
             (この操作を入れなければ次ページのhtmlを読み込まない)
            Application.OnTime Now() + TimeSerial(0, 0, 1), "CloseUserForm"
            UserForm1.Show

            j = j - 1
            
            Application.StatusBar = i & "/" & maxCnt & " _
                                    (" & (Format(i / maxCnt, "0.0%")) & ")"            
        Next i        
        .Columns.AutoFit
        
    End With
    
    Dim EndTime As Date     '処理の終了時刻を格納
    EndTime = Time
    EndTime = EndTime - starttime
 
    MsgBox ("所要時間は" & Minute(EndTime) & "分" & Second(EndTime) & "秒でした")    
    
End Sub

Sub CloseUserForm()
  On Error Resume Next  'ユーザーが閉じてしまった場合の想定
   Unload UserForm1
  On Error GoTo 0
End Sub

「SeleniumBasic」でも同様のことができますが、「SeleniumBasic」では実際にブラウザを操作しますので、非常に時間がかかります。
(2022年7月2日時点での上記時価総額ランキングのトータル件数は約4,000件ですが、これをすべて書き出すのに、「SeleniumBasic」では約15分かかるところ、「HTTP通信」では約2分で済みます)

コメント

タイトルとURLをコピーしました