【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 | 通常のデータセル |

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

見出し行の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で処理すれば、列数を固定値で決める必要がありません。

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アプリから始めませんか?
