2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Power Query へそのゴマAdvent Calendar 2024

Day 12

Power Query へそのゴマ 第12章 Html.Table の CSS セレクター指定によるデータ抽出

Last updated at Posted at 2024-12-11

Html.Table は、Power Query M 言語で提供される関数の一つで、HTML コンテンツからテーブル形式のデータを抽出するために使用します。この関数を利用すると、Web ページに含まれるHTML表(<table> タグ)を解析して、Power Query内で扱えるテーブルデータとして取り込むことができます。

12.1. Html.Table 関数の概要

Html.Table は、HTML データから指定したパターンに基づいてテーブル形式のデータを抽出するための Power Query 関数です。

構文
Html.Table(
    html as any, 
    columnNameSelectorPairs as list, 
    optional options as nullable record
) as table
  • html: HTML コンテンツ(通常は Web.Contents で取得)。
  • columnNameSelectorPairs: 列名と対応する CSS セレクターまたは列データを抽出する式のペアをリスト形式で指定。
  • options: オプション設定で、RowSelector を使用して行単位で抽出条件を指定可能。

12.2. CSS セレクターの基本

CSS セレクターは、HTML 内の特定の要素や属性を指定するための方法です。以下は主要なセレクターです。

基本セレクター

名称 説明
全称セレクター すべての要素 *
要素型セレクター 要素名を指定 input
クラスセレクター class属性を指定 .classname
IDセレクター id属性を指定 #idname
属性セレクター 属性を指定 [attr] [attr=value]

属性セレクター

構文 説明
[attr] その属性を持つ要素 [name]
[attr=value] 指定された属性の値が完全一致
[class="a b c"]は
class="a b c"と一致
[class="bold-01"]
[attr~=value] [class="b"]は
class="a b c"と一致
[class~="red-02"]
[attr|=value] [id|="pre"]は
preとpre-viewと一致
[class|="red"]
[attr^=value] 要素の最初の値に一致 [class^="bold-02"]
[attr$=value] 要素の最後の値に一致 [class$="red-02"]
[attr*=value] [id*="re"]はpreとrenと一致 [class*="old"]
[attr operator value i] 値の大文字と小文字を区別しません [class$="LISTITEM1" i]
[attr operator value s] 値の大文字と小文字を区別します [id="ListItem1" s]

組み合わせセレクター

セレクター 説明
tag.class 特定のタグとクラス div.content
tag#id 特定のタグと ID table#sales
tag[attr=value] 属性が特定の値の要素 a[href="example.com"]

階層セレクター

名称 構文 説明
子孫結合子 A B 子孫にあたるノード #MainContent p
子結合子 A > B 直接の子のノード #MainContent > div > p
一般兄弟結合子 A ~ B Aの後にあるBの要素 p ~ p
隣接兄弟結合子 A + B Aの直後のBの要素 span + p
複数選択 A, B AまたはBの要素 ul, dl

子要素フィルター

構文 説明
:first-child 最初の子要素 #Table-1 > tbody > tr > :first-child
:first-of-type セレクタで指定された
最初の子要素
#Table-1 > tbody td:first-of-type
:last-child 最後の子要素 #Table-1 > tbody > tr > :last-child
:last-of-type セレクタで指定された
最後の子要素
#Table-1 > tbody td:first-of-type
:only-child 子要素が
1つだけのときに取得
:only-of-type セレクタで指定された要素が
1つだけのときに取得
:nth-child() 親要素内にあるセレクタで
引数で指定した要素
#FirstLetter > span:nth-child(2)
:nth-of-type() セレクタと引数で指定された要素 #FirstLetter > p:nth-of-type(2)
:nth-last-child() nth-childを最後から数える #FirstLetter > :nth-last-child(2)
:nth-last-of-type() nth-of-typeを最後から数える #FirstLetter > span:nth-last-of-type(2)

12.3. RowSelector を使用した行単位のデータ抽出

RowSelector は、複数行のデータ抽出を可能にするオプションです。

12.3.1 単純な table 要素の抽出

以下の例では、CSS セレクターと RowSelector を使用してウェブページからデータを抽出します。

Product Price
Widget $50
Gadget $30

上記のテーブルは、trで行が区切られているため、以下の様になります。

let
    // Htmlコード
    Source = "
<table id=""products"">
    <thead>
        <tr>
            <th>Product</th>
            <th>Price</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>Widget</td>
            <td>$50</td>
        </tr>
        <tr>
            <td>Gadget</td>
            <td>$30</td>
        </tr>
    </tbody>
</table>",

    // テーブル作成
    ExtractedTable = Html.Table(
        Source,
        {
            {"Product", "td:nth-child(1)"},
            {"Price", "td:nth-child(2)"}
        },
        [RowSelector = "table#products tbody tr"]
    )
in
    ExtractedTable

image.png

12.3.2 複数のtable要素からの抽出

以下は、2つのtable要素に分かれているデータを1つのテーブルにします。

Electronics

Phone $600
Laptop $1200

Appliances

Microwave $200
Fridge $800
let
    Source = "
<section id=""electronics"">
  <h2>Electronics</h2>
  <table>
    <tr><td>Phone</td><td>$600</td></tr>
    <tr><td>Laptop</td><td>$1200</td></tr>
  </table>
</section>
<section id=""appliances"">
  <h2>Appliances</h2>
  <table>
    <tr><td>Microwave</td><td>$200</td></tr>
    <tr><td>Fridge</td><td>$800</td></tr>
  </table>
</section>",

    Electronics = Html.Table(
        Source,
        {
            {"Product", "td:nth-child(1)"},
            {"Price", "td:nth-child(2)"}
        },
        [RowSelector = "section#electronics table tr"]
    ),

    Appliances = Html.Table(
        Source,
        {
            {"Product", "td:nth-child(1)"},
            {"Price", "td:nth-child(2)"}
        },
        [RowSelector = "section#appliances table tr"]
    ),

    Result = Table.Combine({Electronics, Appliances})
in
    Result

image.png

12.3.4 dlul のリスト要素からの抽出

サンプルページの中で、CSSの修飾でテーブルのように見えているけど、実はリスト要素で作成されているデータも抽出できます。

image.png

HTMLコード
<div id="route">
<h4>id=rsltlst</h4>
<ul id="rsltlst" class="routeList">
  <li>
    <dl>
      <dt>ルート1</dt>
      <dd>
        <ul>
          <li class="time">19:03→<span class="mark">19:38</span><span class="small">35分</span></li>
          <li><span class="mark">726円</span></li>
          <li>乗換:<span class="mark">0回</span></li>
        </ul>
      </dd>
    </dl>
  </li>
  <li>
    <dl>
      <dt>ルート2</dt>
      <dd>
        <ul>
          <li class="time">19:00→<span class="mark">19:38</span><span class="small">38分</span></li>
          <li class="fare"><span class="mark">726円</span></li>
          <li class="transfer">乗換:1回</li>
        </ul>
      </dd>
    </dl>
  </li>
  <li>
    <dl>
      <dt>ルート3</dt>
      <dd>
        <ul>
          <li class="time">18:58→<span class="mark">19:38</span><span class="small">40分</span></li>
          <li class="fare"><span class="mark">726円</span></li>
          <li class="transfer">乗換:1回</li>
        </ul>
      </dd>
    </dl>
  </li>
</ul>
</div>
let
    Source = Web.Contents("https://fukuyori.github.io/RPALT20220117/"),
    MakeTable =
        Html.Table(
            Source,
            {
                {"ルート","dl > dt"},
                {"修正前時刻", "dl > dd > ul > li.time"},
                {"所要時間", "dl > dd > ul > li.time > span.small"},
                {"金額", "dl > dd > ul > li:nth-child(2)"},
                {"乗換", "dl > dd > ul > li:nth-child(3)"}
            },
            [RowSelector = "ul#rsltlst > li > dl"]
        ),

        // 時刻項目の修正
        ItemModification = 
            Table.AddColumn(
                MakeTable,
                "時刻",
                each Text.Replace([修正前時刻], [所要時間], "")
            )
in
    ItemModification

image.png

最後のステップで、「修正前時刻」に入り込んでいる「所要時間」を消す作業を行っています。

12.3.4 特定の属性を抽出する方法

HTML 要素の属性値を抽出するには、CSS セレクターを指定した後、[Attributes][属性名] を付加します。

image.png

HTMLコード
<div id="SideBarLink" class="quicklinks" name="quicklinks">
<div>
  <h3>id=SideBarLink</h3>
  <h4>id=List-1</h4>
  <ul id="List-1" class="list">
    <li id="ListItem1" class="ListItemClass"><a href="http://www.google.com/">google</a></li>
    <li id="ListItem2" class="ListItemClass"><a href="http://www.yahoo.co.jp/">yahoo</a></li>
    <li id="ListItem3" class="ListItemClass"><a href="https://www.bing.com/">bing</a></li>
  </ul>
</div>
let
    Source = Web.Contents("https://fukuyori.github.io/RPALT20220117/"),
    Table =
        Html.Table(
            Source,
            {
                {"Name","li > a"},
                {"URL", "li > a", each [Attributes][href]?}
            },
            [RowSelector = "ul#List-1 > li"]
        )
in
    Table

image.png

{"URL", "li > a",each [Attributes][href]?}の行では、3番目の部分で全ての属性から href を選び出しています。該当の値が存在しない場合、このステップがエラーとなってしまい、クエリが止まってしまいます。? をつけておくと、該当の値が存在しない場合には null が返され、エラーを回避できます。

12.4 ベストプラクティス

1. 行選択の精度を上げる

  • RowSelector を使用することで、ターゲットとなる行を正確に指定します。これにより、不要なデータを抽出するリスクを軽減できます。

2. セレクターの構造を確認

ブラウザの「要素を検証」機能を活用して、ページの DOM 構造に基づいて適切なセレクターを特定します。

CSSセレクターを適切に指定するためには、以下のツールを活用すると効果的です。

  • CSSセレクターのコピー: HTML構造を確認し、要素を特定するのに役立ちます。

    • Google Chrome: 要素を右クリック → 検証 → 要素のコードを右クリック → Copy → Copy selector
      image.png

    • Microsoft Edge: 要素を右クリック → 開発者ツールで調査する → 要素のコードを右クリック → コピー → selectorをコピー
      image.png

  • セレクターテストツール: CSSセレクターをテストするツールを使用して、正確なセレクターを確認します。

    • Google Chrome:
      • Ctrl + Shift + i (Option + Command + i) を押してデベロッパー ツール起動。
      • Consoleを選択。
      • cssセレクターの実験は $$(css_selector);
        image.png
    • Microsoft Edge:
      • Ctrl + Shift + i (Option + Command + i) を押して開発者ツール起動。
      • コンソールを選択。
      • cssセレクターの実験は $$(css_selector);
        image.png

3. 動的ページに注意

  • JavaScript によって生成されたコンテンツがある場合、Web.BrowserContents を使用する必要がある場合があります。
2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?