2017-04-24

HTMLテーブルからのデータ抽出

「データセットの再編成 - 水系域別河川データセットの作成」「トポロジーに関するGISデータ品質の検査」で使用した国土数値情報「河川」データセットの全てのフィーチャー (河川端点、流路) は、属性として水系域コードを持っており、その値に基づいて水系域別に出力先ファイルを振り分けたり、特定の水系域に属するフィーチャーのみを抽出したりできました。

国土数値情報ダウンロードサービスサイトでは、水系域コードの一覧表 (コードと名称の対応表) を掲載したウェブページも公開されているので、そのソース (HTML文書) から表の内容を抽出すれば、水系域コードをキーとして水系域の名称も取得できるようになります。

FME 2016 以前でも、HTMLをXMLとして解析したり文字列処理を施したりすることによって、HTML文書から必要なデータを抽出することはできましたが、FME 2017 では、新たに HTMLExtractor トランスフォーマーが導入され、より簡単に、HTML文書から特定の要素またはその内容を抽出できるようになりました。

この HTMLExtractor を使い、HTML形式の水系域コード一覧表から各行の内容 (コードと名称) を抽出し、Excel形式のファイルに出力するワークスペース例を掲げます。

FME 2017.0.0.2 build 17280

ソースHTML文書の <table> 要素 (水系域コード一覧表が記述されている部分)
http://nlftp.mlit.go.jp/ksj/gml/codelist/WaterSystemCodeCd.html から引用 (2017-04-21)
<table border="1" cellspacing="0" cellpadding="5">
  <tr align="center">
    <td  bgcolor="#CCCCCC" width="100" ><b>コード</b></td>
    <td  bgcolor="#CCCCCC" width="300"><b>対応する内容</b></td>
      </tr>

<td>010001</td><td>ウエンナイ川</td></tr>
<tr>
<td>010002</td><td>声問川</td></tr>
<tr>
<td>010003</td><td>増幌川</td></tr>

(中略)

<tr>
<td>890918</td><td>大野川</td></tr>
<tr>
<td>890919</td><td>大分川</td></tr>
<tr>
<td>890920</td><td>山国川</td></tr>

 </table>

FMEワークスペース例





















Creator: フィーチャーを1個出力する。
HTTPCaller: 水系域コード一覧表を掲載しているHTML文書を取得する。
HTMLExtractor: HTML文書から全ての <tr> 要素 (表の行) を抽出してリスト属性に格納する。
AttributeKeeper: 不要な属性を削除する (リスト展開時の無用なデータコピーを防ぐため)。
ListExploder: リストを展開して行ごとのフィーチャーを作成する。
Tester: 最初の行 (列名) を除く。
StringSearcher: <td> 要素 (列) の値を抽出する (1行あたり2列)。
[XLSXW] ライター: Excel形式でファイルに出力する。


HTTPCaller は、フィーチャーを受け取ったときに Request URL パラメーターで指定されたURLに対してリクエストを発行し、ウェブサーバーからのレスポンスを格納した属性をフィーチャーに与えて出力します。水系域一覧表を掲載しているウェブページのURLを指定してGETメソッドのリクエストを発行すれば、レスポンスとして、そのURLのHTML文書全体が取得できます。

HTMLExtractor では、パラメーターを次のように設定することにより、取得したHTML文書から全ての <tr> 要素 (表の行) を抽出し、それらをリスト属性 _tr{} に格納しました。

HTMLExtractor パラメーター設定例




























_tr{} リストの各要素には、次のように2つの <td> 要素 (データ) を含む <tr> 要素 (行) が格納されます。

リスト要素値 = HTML文書から抽出された <tr> 要素
_tr{0}<tr align="center">
<td bgcolor="#CCCCCC" width="100"><b>コード</b></td>
<td bgcolor="#CCCCCC" width="300"><b>対応する内容</b></td>
</tr>
_tr{1}<tr>
<td>010002</td><td>声問川</td></tr>
_tr{2}<tr>
<td>010003</td><td>増幌川</td></tr>
(中略)

_tr{5473}<tr>
<td>890918</td><td>大野川</td></tr>
_tr{5474}<tr>
<td>890919</td><td>大分川</td></tr>
_tr{5475}<tr>
<td>890920</td><td>山国川</td></tr>
注: 水系域コード 010001「ウエンナイ川」の行が _tr{} リストに格納されませんでしたが、それは、ソースHTML文書において、当該水系域の行のための <tr> タグが欠落していたためです (2017-04-21時点)。ウェブブラウザは、この程度の欠落は自動的に補ったうえで画面表示しますが、HTMLExtractor には、そのような補完機能はありません。完全な一覧表を得るには、<tr> タグを補って修正したHTML文書を使うか、あるいは、 <tr> 要素でなく <td> 要素を抽出する (コード、名称を交互にひとつのリストに格納する) などの別のアプローチを考える必要があります。


AttributeKeeper で不要な属性を削除した後、ListExploder で _tr{} リストを展開すると、その要素数と同じ数だけフィーチャーがコピーされるとともに、リストの各要素の値がコピーされたフィーチャーの _tr 属性 (リスト名から {} を除いた名前) に配分されます。また、各フィーチャーには、元のリストにおける各要素のインデクス (0 から始まる連番) を格納した属性も付加されます。

Tester で先頭の行 (ウェブブラウザ画面上での列名表示用、リストの要素インデクス = 0) を除外してから、残りの全ての行について StringSearcher によって列 (<td> 要素 x 2) の内容 (コード、名称) を抽出しました。

StringSearcher パラメーター設定例























主要なパラメーターは、次の三つです。

  • Search In (元の文字列を格納している属性): _tr
  • Contains Regular Expression (抽出したい部分文字列に一致する正規表現): <td>(.+?)</td>
  • Subexpression Matches List Name (部分式に一致した部分文字列と位置を格納するリスト名): _td

_tr 属性の値 (<tr> 要素) には、Contains Regular Expression パラメーターに設定した正規表現に一致する部分文字列 (<td> 要素) が2つ含まれており、部分式 (正規表現内の丸カッコで囲んだ部分) に一致する部分文字列 (<td> 要素の内容) とその位置 (元の文字列の先頭を 0 とする部分文字列先頭文字のインデクス) が _td リスト (_td{}.part, _td{}.startIndex) に格納されます。つまり、水系域コードと名称、および、それらの位置 が次の要素に格納されることになります。

  • _td{0}.part: 水系域コード (正規表現の部分式に一致した部分文字列)
  • _td{0}.startIndex: 元の文字列における水系域コードの先頭の文字の位置
  • _td{1}.part: 水系域名称 (正規表現の部分式に一致した部分文字列)
  • _td{1}.startIndex: 元の文字列における水系域名称の先頭の文字の位置

これらのうち _td{0}.part_td{1}.part を StringSearcher のインターフェース上に現し (脚注1参照) 、それぞれ、Excelライターフィーチャータイプの対応する属性に接続 (マッピング) すれば、完成です。

実行結果 (Excelスプレッドシート)



注1: Workbench キャンバス上のトランスフォーマーのインターフェースに表示されているリスト属性名の右クリックメニュー > Expose Elements (リストの要素を現す) から Select List Elements (リスト要素の選択) 画面を開き、インデクスを指定 (単独、最初と最後のインデクスをハイフンで連結した範囲、それらのカンマ区切りによる複数指定可) することによって、任意の要素をインターフェースに現すことができます (下図参照)。















注2: ListExploder によってフィーチャーに配分される _tr 属性の値 (HTML <tr> 要素) は、XML断片 (XML fragment) として扱うことができるので、StringSearcher の代わりに XMLFlattener によって <td> 要素の内容を抽出することもできます。その場合に作成されるリスト属性名はHTML (XML) 要素名と同じ td{} となり、水系域コードと名称は、次の要素に格納されます。
  • td{0}: 水系域コード
  • td{1}: 水系域名称

XMLFlattener パラメーター設定例





















0 件のコメント:

コメントを投稿