【Excel VBA】ウェブスクレイピングの紹介(2/2)

Excel VBA

プログラム紹介(続き)

本記事は、前回記事で紹介したウェブスクレイピング記事の続きです。前回記事をご覧になっていない方はまずそちらをご覧ください。

本記事では下記コードのポイント(7)~(11)について説明します。

Option Explicit
Declare PtrSafe Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)

Sub get_list()

  'ポイント(1) InternetExplorerオブジェクトの生成
  Dim objIE As InternetExplorer
  Set objIE = New InternetExplorer
     
  'ポイント(2) 京のまち企業訪問ホームページを開く
  objIE.Visible = True
  objIE.Navigate "https://www5.city.kyoto.jp/kigyo/kg_102.cgi?CT=20&PN=1"

  'ポイント(3) ページが進む前に次の動作が始まるのを防ぐ
  Do While objIE.Busy = True Or objIE.readyState < READYSTATE_COMPLETE
    DoEvents
  Loop
  
  'HTMLDocumentオブジェクトの生成
  Dim htmlDoc As HTMLDocument
  Set htmlDoc = objIE.document
  
  'ポイント(4) Excelシートの行数を格納する変数
  Dim counter_Excelrow As Integer
  'ポイント(5) ホームページのページ番号を格納する変数
  Dim counter_IEpage As Integer
  
  '1行目はリストのため、2行目からスタート
  counter_Excelrow = 2
  '1ページ目は既に開いているため、2ページ目からスタート
  counter_IEpage = 2
  
  'ポイント(6) データを抜き出すページ数に合わせて繰り返し回数を設定する (本プログラムでは10ページ分)
  '2022年4月時点の掲載企業3956件を全て網羅したい場合は400回試行が必要だが、注意が必要
  For counter_IEpage = 2 To 10
  
    Do While objIE.Busy = True Or objIE.readyState < READYSTATE_COMPLETE
      DoEvents
    Loop

    Dim i As Integer
    
    'ポイント(7) 1ページの企業数(10件)の数だけ試行を繰り返す
    For i = 0 To 9

      'Withステートメントを用いてオブジェクトの複数記載を省略
      'Class名を利用して企業情報にアクセス
      With ThisWorkbook.Worksheets(1)
        .Cells(counter_Excelrow, 1).Value = htmlDoc.getElementsByClassName("colset_article_ttl")(i).innerText
        .Cells(counter_Excelrow, 2).Value = htmlDoc.getElementsByClassName("colset_article_txt")(i).innerText
        'ポイント(8) Replace関数 & Mid関数を用いて不要な部分を削除
        .Cells(counter_Excelrow, 3).Value = Replace(Mid(htmlDoc.getElementsByClassName("colset_article_access")(i).innerText, 7), vbLf, "")
      End With
      
      '次の読み込みのため、企業情報を記録するExcelシートの行を1行下げる
      counter_Excelrow = counter_Excelrow + 1

        'ポイント(9) エラーが発生しても、無視して次のステップに進む
        On Error Resume Next

     Next

      Do While objIE.Busy = True Or objIE.readyState < READYSTATE_COMPLETE
        DoEvents
      Loop
      
      'ポイント(10) アクセス間隔を1秒開ける
      Call Sleep(1000)

      'ポイント(11) 次のページに進む
      objIE.Navigate "https://www5.city.kyoto.jp/kigyo/kg_102.cgi?CT=20&PN=" & counter_IEpage & "&RDNG=&RDNG2="
    
  Next
  
End Sub

ポイント(7) 1ページの企業数(10件)の数だけ試行を繰り返す

今回のウェブスクレイピングは下記の方針で進めていきます。

  1. ホームページの企業情報が掲載されているエリアのHTMLから「会社名」、「本社所在地」および「スローガン」を抽出し、Excelファイルに記入する
  2. 手順1の抽出作業をホームページに掲載されている企業の数だけ繰り返す
  3. 次ページに遷移し、手順1, 2を繰り返す
  4. 最後の企業情報を抽出したら試行を終了する

1ページあたりの企業情報の掲載件数は10件のため、手順2の試行回数は10回必要となります。

表示件数を10件から100件に変更した方がページ遷移回数が減り、不要なアクセスを抑えられるため、ベターです。その場合は、表示件数を10件から100件に変更するステップが追加で必要になります。

ポイント(8) Replace関数 & Mid関数を用いて不要な部分を削除

本社所在地をHTMLから抽出すると、本当に住所の部分だけでなく”本社所在地”といった不要な情報も含まれています。したがって、Replace関数 & Mid関数を用いて必要な部分だけを抽出しています。

ポイント(9) エラーが発生しても、無視して次のステップに進む

最終ページに10件のデータがあればエラーが発生することはありませんが、10件未満の場合は企業データを読み込むことができずエラーとなります。今回はエラーが発生しても試行を止めず、最後までスクリプトを完了させます。企業情報を読み込んでいない実際には不要な試行を実施していることになっていますが、最も分かりやすい考え方だと思います。

ポイント(10) アクセス間隔を1秒開ける

アクセス間隔の制御を行わずにウェブスクレイピングをすると、ページの読み込みが立て続けに実施されることになります。人間がウェブページの閲覧をしている範囲内でこのような挙動は発生しないため、コンピュータによるDoS攻撃と判定される可能性があります。

アクセス間隔を設定するための方法として、Sleep関数が使えます。Sleep関数はExcelの関数ではなくWindows APIと呼ばれる外部の関数のため、呼び出す形式で使用します。

Declare PtrSafe Sub Sleep Lib “kernel32” (ByVal dwMilliseconds As Long)という決まり文句が必要になりますので、スクリプトの先頭で忘れずに宣言しておいてください。

ポイント(11) 次のページに進む

ページ遷移のために用意したcounter_IEpage変数を用いて小さいページ番号から順番に読み込みを行っていきます。多くのケースではClickメソッドを用いてページ遷移しますが、今回はHTMLがClickメソッドに対応していませんでした。その代わり、本ホームページではページ数に対応したURLが設定されていたため、URLを次々に読み込んでいく形式にしました。

まとめ

今回のウェブスクレイピングの記事はいかがでしたでしょうか?ウェブスクレイピングのやり方は必ずしも1つではなく、複数のアプローチが可能です。

皆様も利用規約をしっかりと確認したうえで、いろいろなホームページでウェブスクレイピングを試してみてください!

コメント

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