【Excel VBA×Selenium】WebページのテーブルをExcelへ一覧取得する方法|table・tr・tdを繰り返し取得

みなさんこんにちは。

Excel VBA×SeleniumでWebスクレイピングをしていると、Webページ上に表示されている表形式のデータを、そのままExcelへ一覧として取得したい場面があるかと思います。

例えば、商品一覧、料金表、検索結果、管理画面の一覧などでは、HTMLの table・tr・td を使用してデータが表示されていることがあります。

今回は、table→tr→tdというHTML構造の確認方法から、行ループ×列ループでExcelへ転記する方法について、見出し行・空セル・列数が変わる場合の考え方まで順番にご紹介したいと思います。


この記事はこんな人におすすめ

  • VBA×SeleniumでWebページの表をExcelへ取得したい人
  • table・tr・tdの意味がよく分からない人
  • 複数行・複数列のデータを繰り返し取得したい人
  • Webスクレイピングで一覧データを自動収集したい人
  • 見出しや空セルを含むテーブルを扱いたい人

table・tr・tdのHTML構造を確認する

一般的なHTMLテーブルは、以下のような構造になっています。

<!-- 表全体を表すtableタグ -->
<table id="table1">

    <!-- 見出し部分 -->
    <thead>
        <tr>
            <!-- 各列の見出しをthタグで定義 -->
            <th>氏名</th>
            <th>部署</th>
            <th>メールアドレス</th>
        </tr>
    </thead>

    <!-- 実際のデータ部分 -->
    <tbody>
        <tr>
            <!-- 1行分のデータをtdタグで定義 -->
            <td>山田 太郎</td>
            <td>営業部</td>
            <td>yamada@example.com</td>
        </tr>
    </tbody>

</table>
タグ意味
table表全体
tr表の1行
th見出しセル
td通常のデータセル
Chrome DevToolsでWebページのtable・tr・tdのHTML構造を確認した画面

Seleniumで対象のtableを取得する

'取得対象となるtable要素を格納する変数
Dim tableElement As Selenium.WebElement

'id="table1"のtable要素を取得する
Set tableElement = driver.FindElementById("table1")

idがない場合は、FindElementByXPathやFindElementByCssなど、対象ページのHTML構造に合った方法で取得してください。

trを取得して行単位で繰り返す

'table内の複数のtr要素を格納する変数
Dim rows As Selenium.WebElements

'現在処理している1行分のtr要素を格納する変数
Dim rowElement As Selenium.WebElement

'table内に存在するtr要素をすべて取得する
Set rows = tableElement.FindElementsByTag("tr")

'取得したtr要素を1行ずつ繰り返し処理する
For Each rowElement In rows

    '確認用として、現在の行に含まれる文字列をイミディエイトウィンドウへ出力する
    Debug.Print rowElement.Text

Next rowElement

FindElementsを使用すると、条件に一致する複数の要素をコレクションとして取得できます。Selenium公式ドキュメントでも、複数要素を取得したあとに繰り返し処理する方法が案内されています。

trの中からtdを取得する

'1行の中に存在する複数のtd要素を格納する変数
Dim cells As Selenium.WebElements

'現在処理している1セル分のtd要素を格納する変数
Dim cellElement As Selenium.WebElement

'取得済みの行を1行ずつ処理する
For Each rowElement In rows

    '現在の行に含まれるtd要素をすべて取得する
    Set cells = rowElement.FindElementsByTag("td")

    '取得したtd要素を1セルずつ処理する
    For Each cellElement In cells

        '確認用としてセルの文字列をイミディエイトウィンドウへ出力する
        Debug.Print cellElement.Text

    Next cellElement

Next rowElement

外側のFor Eachが行のループ、内側のFor Eachが列のループになります。

取得したテーブルをExcelへ出力する

'Excelへ出力する行番号
Dim outputRow As Long

'Excelへ出力する列番号
Dim outputCol As Long

'1行目は見出しとして使用するため、データは2行目から出力する
outputRow = 2

'Webテーブルの行を1行ずつ処理する
For Each rowElement In rows

    '現在の行に含まれるtd要素をすべて取得する
    Set cells = rowElement.FindElementsByTag("td")

    'tdが存在する行だけExcelへ出力する
    If cells.Count > 0 Then

        '新しい行を処理するたびに、出力列をA列へ戻す
        outputCol = 1

        '現在の行に含まれるセルを左から順番に処理する
        For Each cellElement In cells

            '取得した文字列をExcelの対応するセルへ出力する
            Worksheets("Sheet1").Cells(outputRow, outputCol).Value = _
                cellElement.Text

            '次のExcel列へ移動する
            outputCol = outputCol + 1

        Next cellElement

        '1行分の出力が終わったら、Excelの次の行へ移動する
        outputRow = outputRow + 1

    End If

Next rowElement
Excel VBA×SeleniumでWebテーブルのtd要素を繰り返し取得してExcelへ一覧出力した画面

見出し行のthもExcelへ取得する

'見出しとなる複数のth要素を格納する変数
Dim headers As Selenium.WebElements

'現在処理している1つのth要素を格納する変数
Dim headerElement As Selenium.WebElement

'Excelへ出力する列番号
Dim colNum As Long

'table内に存在するth要素をすべて取得する
Set headers = tableElement.FindElementsByTag("th")

'見出しはExcelのA列から出力する
colNum = 1

'取得した見出しを左から順番に処理する
For Each headerElement In headers

    'Webテーブルの見出しをExcelの1行目へ出力する
    Worksheets("Sheet1").Cells(1, colNum).Value = headerElement.Text

    '次の列へ移動する
    colNum = colNum + 1

Next headerElement

一連のサンプルコード

Sub GetWebTable()

    '==================================================
    ' 変数を定義する
    '==================================================
    'SeleniumでChromeを操作するためのWebDriver
    Dim driver As New Selenium.WebDriver

    '取得対象のtable要素
    Dim tableElement As Selenium.WebElement

    'table内の複数行を格納する
    Dim rows As Selenium.WebElements

    '1行内の複数セルを格納する
    Dim cells As Selenium.WebElements

    'table内の見出しを格納する
    Dim headers As Selenium.WebElements

    '現在処理している1行分の要素
    Dim rowElement As Selenium.WebElement

    '現在処理している1セル分の要素
    Dim cellElement As Selenium.WebElement

    '現在処理している1つの見出し要素
    Dim headerElement As Selenium.WebElement

    '取得結果を出力するExcelシート
    Dim ws As Worksheet

    'Excelへ出力する行番号
    Dim outputRow As Long

    'Excelへ出力する列番号
    Dim outputCol As Long

    '==================================================
    ' 出力先となるExcelシートを準備する
    '==================================================
    '取得結果の出力先をSheet1に設定する
    Set ws = ThisWorkbook.Worksheets("Sheet1")

    '前回取得したデータが残らないように、既存データを削除する
    ws.Cells.ClearContents

    '==================================================
    ' Chromeを起動して対象ページを開く
    '==================================================
    'Chromeを起動する
    driver.Start "Chrome"

    'テーブル取得用のサンプルページを開く
    driver.Get "https://the-internet.herokuapp.com/tables"

    'ページが表示されるまで1秒待機する
    driver.Wait 1000

    '==================================================
    ' 対象となるtable要素を取得する
    '==================================================
    'id="table1"のtable要素を取得する
    Set tableElement = driver.FindElementById("table1")


    '==================================================
    ' Webテーブルの見出しをExcelへ出力する
    '==================================================

    'table内に存在するth要素をすべて取得する
    Set headers = tableElement.FindElementsByTag("th")

    '見出しはExcelのA列から出力する
    outputCol = 1

    '取得した見出しを左から順番に処理する
    For Each headerElement In headers

        '見出し文字列をExcelの1行目へ出力する
        ws.Cells(1, outputCol).Value = headerElement.Text

        '次の列へ移動する
        outputCol = outputCol + 1

    Next headerElement


    '==================================================
    ' Webテーブルのデータ行を取得する
    '==================================================

    'table内に存在するtr要素をすべて取得する
    Set rows = tableElement.FindElementsByTag("tr")

    'データは見出しの次となるExcelの2行目から出力する
    outputRow = 2


    '==================================================
    ' 行ループ × 列ループでExcelへ転記する
    '==================================================

    'Webテーブルの行を1行ずつ処理する
    For Each rowElement In rows

        '現在の行に含まれるtd要素をすべて取得する
        Set cells = rowElement.FindElementsByTag("td")

        'tdが存在する行だけ出力する
        '見出し行はthで構成されているため、この条件で除外される
        If cells.Count > 0 Then

            '新しい行を処理するたびに、出力列をA列へ戻す
            outputCol = 1

            '現在の行に含まれるセルを左から順番に処理する
            For Each cellElement In cells

                'Webページから取得した文字列をExcelへ出力する
                ws.Cells(outputRow, outputCol).Value = cellElement.Text

                '次のExcel列へ移動する
                outputCol = outputCol + 1

            Next cellElement

            '1行分の出力が終わったら、Excelの次の行へ移動する
            outputRow = outputRow + 1

        End If

    Next rowElement


    '==================================================
    ' 処理完了を通知する
    '==================================================

    MsgBox "テーブルの取得が完了しました。", vbInformation

End Sub

空セルがある場合

td要素自体が存在して中身が空の場合は、cellElement.Textが空文字として取得されます。空セルを「-」などに置き換えたい場合は条件分岐を入れることもできます。

'取得したセルが空文字か確認する
If Trim(cellElement.Text) = "" Then

    '空セルの場合は「-」をExcelへ出力する
    ws.Cells(outputRow, outputCol).Value = "-"

Else

    '値が存在する場合は取得した文字列をそのまま出力する
    ws.Cells(outputRow, outputCol).Value = cellElement.Text

End If

行ごとに列数が違う場合

実際のWebサイトでは、すべての行が同じ列数とは限りません。今回のように各行ごとにtdを取得し、取得できた件数だけFor Eachで処理すれば、列数を固定値で決める必要がありません。

Excel VBA×SeleniumでWebテーブルの見出しとデータをExcelへ一覧取得した完成画面

tableタグを使っていない一覧にも注意

画面上では表に見えていても、HTML上ではtable・tr・tdではなく、divタグなどで作られているWebサイトもあります。その場合はDevToolsで実際のHTML構造を確認して、class・XPath・CSSセレクタなどを使用してください。

規則性のある複数要素を取得する考え方については、以下の記事でもご紹介しています。

複数ページのテーブルを取得する場合

一覧が複数ページに分かれている場合は、今回のテーブル取得処理とページネーション処理を組み合わせることができます。

要素を取得できるまで待機する場合

JavaScriptでテーブルを後から読み込むページでは、tableやtrが表示されるまで待機してから取得すると安定しやすくなります。

よくある原因と確認ポイント

状況確認するポイント
tableが取得できないid・XPath・CSSセレクタが正しいか確認する
見出しが取得できないtdではなくthになっていないか確認する
一部の列が空になる元のtdが空セルではないか確認する
行ごとに列数が違う各trごとにtdを取得して件数分だけループする
画面上は表なのにtableがないdivなど別のHTML構造で作られていないか確認する
最初の数件しか取得できないページネーションや遅延読み込みがないか確認する

参考情報

最後に

いかがでしたでしょうか。

今回は、Excel VBA×Seleniumを使用して、Webページ上のtable・tr・tdを繰り返し取得し、Excelへ一覧出力する方法についてご紹介しました。

Webテーブルの取得では、table→tr→tdというHTMLの親子関係を意識して、行と列を2重ループすることがポイントです。

商品一覧や検索結果、管理画面など、さまざまな表形式のデータ取得へ応用できますので、少しでも参考になれば幸いです。


開発依頼について

ココナラでWebスクレイピング開発サービスを出品しております。

自分で開発をしようと思ったけど、VBAでのネット記事が少なく困っている方も多いかと思います。

そんな方はいつでもお気軽にご相談ください。

また、本ブログからご依頼いただいた方については割引特典がございますので、

ご不明点と合わせてメッセージをいただけると幸いです。

Excelにてブラウザ操作自動化ツールを作成します その作業、webスクレイピングを使って自動化しましょう!

Webスクレイピング以外にもWebアプリの開発サービスも出品しております。

こちらについても、本ブログからご依頼いただいた方については割引特典がございますので、

お気軽にご相談ください。

スモールスケールのWebアプリ開発します 先ずはスモールスケールのWebアプリから始めませんか?

ご興味がある方はこちら!!

コメントを残す

メールアドレスが公開されることはありません。 ※ が付いている欄は必須項目です

CAPTCHA