配列を使ってテーブルの情報を取得する
Webスクレイピングの際は各URLによって色々なテーブル(表)から情報を取得する事になります。
通常であれば同じURL内でも様々なテーブル(表)があるのでテーブルごとにコードを用意します。
- 行が一定ではない
- 列が一定ではない
- 表の情報量が多い、少ない
思いつくだけでも3~4通りほどのケースがあります。
繰り返し処理などを使いテーブルごとにコードを用意するのは非常に手間がかかるのでなんとか避けたいものです。
ケースごとにマクロを構築するのかと思うとモチベーションが下がりますよね。
開発時はモチベーションが高いので乗り切れますが修正時にコードに多いのは大変です。
そんな時の解決策を用意しました。「テーブルごと配列に格納する」という方法です。
これで構想、コードの作成が楽になります。ケースごとにコードを用意しなくても良いので時短になります。
追加でテーブルの行数と列数も獲得する事ができる様にしました。
すごく簡単に行列の情報を取得できるので合わせて紹介する事にします。
今回はテーブルを扱うのでHTMLの説明もしています。よってコードに辿り着くのが少々遠いです。
すぐに事例やコードを見たいという方はこちらにどうぞ。
関連情報
紹介するコード内では2次元配列を使います。よって2次元配列に関する記事を用意しておきます。
配列が良く分からないという方はまずこちらの記事をご覧ください。
コピーして使うだけで配列のスピードが体感できるコードも用意しています。
配列を使ってみよう【検索にも使える】VBAの2次元配列で作業の高速化を実現させる
もう1つの関連記事です。
今回はテーブルごと情報を取り出しますがテーブルの行列を1つずつループして値を取り出す事も可能です。
関連記事VBA×Chrome/Edgeでスクレイピング|XPathとは?|動画で解説
テーブルとは
ChatGPTに質問してみました。まずはHTMLはどこに公式ドキュメント(文書)があるのかを確認しました。
回答によるとHTMLにも公式ドキュメント(文書)があるようです。
HTML(Hypertext Markup Language)の公式ドキュメントは、World Wide Web Consortium(W3C)と呼ばれる国際的な標準化団体によって管理されています。W3Cのウェブサイト上でHTMLの仕様やドキュメントが公開されています。以下がそのリンクです:
HTMLの最新の仕様(HTML Living Standard): https://html.spec.whatwg.org/multipage/
HTML5の仕様(旧バージョン): https://www.w3.org/TR/html52/
HTML4の仕様(さらに古いバージョン): https://www.w3.org/TR/html4/
HTMLの仕様は定期的に更新され、新しいバージョンがリリースされることがあります。最新の情報にアクセスするためには、HTML Living Standardを参照することがおすすめです。また、W3Cのウェブサイトでは他の関連するウェブ技術の仕様も提供されています。
ChatGPT:HTMLの公式ドキュメントはどこにありますか?
提示してもらった最新の仕様を確認してみました。ものすごく長い文章なので探すのが大変でした。
基本英語です。得意な方はチャレンジしてみてください。
The
table
element represents data with more than one dimension, in the form of a table.
Thetable
element takes part in the table model. Tables have rows, columns, and cells given by their descendants. The rows and columns form a grid; a table’s cells must completely cover that grid without overlap.上の文章をGoogle翻訳で和訳しました。以下ご覧ください。
「Table 要素は、複数の次元を持つデータをテーブルの形式で表します。 table 要素はテーブル モデルに参加します。テーブルには、その子孫によって与えられた行、列、セルがあります。行と列がグリッドを形成します。テーブルのセルは、重なり合うことなくグリッドを完全にカバーする必要があります。」
HTML Living Standard — Last Updated 11 September 2023 4.9.1 The table element
できるだけ簡単に言いますとテーブルは「行、列をもったグリッド状の要素の総称」です。
見た目でテーブルを理解する
定義は難しいので見た目でテーブルを認識したいという方にはこちらです。
Bootstrapというサイトを紹介します。
簡単に言うとHTMLやCSSのテンプレートが用意されたサイトです。
WordPressではテーマやスキンが豊富なのであまり使う事はないのですがすごく有名なサイトです。
イチからサイトをデザインしなくてもテンプレートの組み合わせでHPを作成する事ができます。
BootstrapのHome画面はこちらからアクセス可能です
こちらにもテーブルのテンプレートが用意されています。
見ていただくとすぐ例が出てきます。エクセルのセルみたいな画像の下にコードが沢山ならんでいます。
今回のコードは<table>~</table>までの情報を1回で引き抜く事ができます。
こうやって見ると便利さが分かりますね。
テーブルごとスクレイピングする
テーブルという単位で情報を引き抜くことができれば行、列ごと一気にスクレイピングが可能という事です。
加えてテーブルはグリッド状に情報を持っているので配列とも相性が良いです。
Seleniumbasic(セレニウムベーシック)にはテーブルを扱うクラスが存在します。
テーブルの情報をそのまま配列に格納する事が出来れば手数は格段に減ります。コードもスッキリします。
事例紹介
私のブログ内にある環境(記事)を使ってテーブルから情報を取得します。
サンプル記事【Selenium×VBA】要素の有無を確認|実行時エラー7への対策
テーブルにピンポイントでリンクを貼ってあるのですぐ確認いただける様にしてあります。
続いて今回のコードの注意点を紹介しておきます。以下事例の際は今回のコードが使えません。
Tableタグの中にtbodyタグが無い時は今回紹介するコードは使用できません。
→tbodyタグがないテーブルはFor~Nextステートメントを駆使して1つずつ情報を取り出す事になります。
多くの事例でtbodyタグを使ってコードが組まれているのでほとんど心配ないのですが紹介だけしておきます。
tbodyタグは行方向の情報を作っているタグです。
スクレイピングの際tbodyタグを使って要素を認識しているので無いとエラーになるという見立てです。(予測)
コード
コードを紹介します。ボタンを押すとコードがコピーできます。
私はChromeを使用していますがEdge等他のブラウザでも同じクラスを保有しています。
よってブラウザ違いでも同じ操作が出来ます。
Sub テーブル取得()
Dim dvr As New ChromeDriver
Dim ary() As Variant
Dim r As Long
Dim c As Long
With dvr
.Start "chrome"
.Get "https://www.slt-pgming-21.net/2023-08-28-010000/"
'スクロール
.ExecuteScript "return document.querySelector" _
& "('#sample_table > div > table').scrollIntoView ({behavior:'smooth' ,block:'center' })"
.Wait 2000
'テーブルの値を配列に格納する
ary() = .FindElementByXPath _
("/html/body/div[1]/div[3]/div/main/article/div/div[17]/div[2]/figure/div/table").AsTable.Data
'2次元配列内の添え字を取得する
r = UBound(ary, 1)
c = UBound(ary, 2)
'セルA1起点で貼り付ける
Range(Cells(1, 1), Cells(1 + r - 1, 1 + c - 1)) = ary
End With
End Sub
解説
やっている事は4つです。ひとつずつ説明します。
- スクロール
- テーブルの値を配列に格納する
- テーブルの行、列を取得
- セルに貼り付け
1_スクロール
用意したコード内では画面スクロールを使っています。VBAの中でJavascriptを実行しています。
動的な操作ができる【VBA×selenium×JS】任意の要素まで簡単にスクロール
2_テーブルの値を配列に格納する
テーブル×配列の説明をする前に「なぜ配列を使うのか」について説明しておきます。
その後コードの解説となります。
配列は高速化以外にも使い道がある
テーブルの値を配列に格納します。基本的にWebスクレイピングでは作業の高速化を狙いません。
作業性をあげて高速で1つの情報にアクセスすると事件に発展する可能性があるからです。
スクレイピング自体は各サイトの規約を守り正しく使えば問題は無いです。安心してください。
上記のような環境の中作業の高速化ができる配列をなぜ使うのか?という質問を受けたことがあります。
値を柔軟に格納出来るのと出力もコントロールできるからです。
今回はテーブルの情報をすべてワークシートに出力しますが必要な情報だけ出力することも可能です。
よって使わない手は無いのでここでも配列を使用する事にします。
今回のコードではテーブルの情報をすべて受け取る為の受け皿として配列を使っています。
コードの解説
オブジェクトブラウザーを使ってコードを解説します。
最初にChromeDriverクラスのFindElementByXPathメソッドでWebElementを取得します。
続いてWebElementクラスのAsTableメソッドでTableElementを取得します。
最後にTableElementクラスのDataメソッドで配列にデータを送る準備をします。
Variant型のデータなのでそのままVariant型で定義した配列aryに代入します。
最終的にはテーブル内の全ての項目ごと配列に取り込む事ができました。
3_テーブルの行、列を取得
Ubound(配列)では対象の配列におけるインデックス番号の最大値を取得する事ができます。
Lbound(配列)では対象の配列におけるインデックス番号の最小値を取得する事ができます。
コード内では(ary,1)、(ary,2)という使い方をしています。
これは配列の1次元目の要素と2次元目の要素を指定しています。
今回のテーブルでは1次元目で行、2次元目で列を取得できます。
簡単にテーブルの行数と列数を取得する事ができますね。
4_セルに貼り付け
単純にセルに貼り付けしたいのですが配列と同じ大きさを定義して貼り付けないとエラーになります。
今回はセルA1を起点に貼り付けるというコードにしています。皆様の事例に合う様に加工してください。
シートを指定すれば任意のシートに値を貼り付ける事も可能です。
まとめ
これでテーブルが沢山あってもスクレイピングが楽になります。TRYしてみてください。
配列さえ理解していれば特に難しいところも無いので簡単に導入していただける事でしょう。
配列が難しいという方はこちをご覧ください。1次元配列の記事を用意しています。