LoginSignup
4
4

More than 5 years have passed since last update.

Node.js で html の表の中身を CSV 形式に加工する

Last updated at Posted at 2017-06-27

はじめに

Node.js で html の表の内容を CSV 形式に加工し、ファイルシステムに保存するスクリプトを作成しました。

当初は、スクレイピングツールのように動的に Web サイトから HTML を取得する想定でしたが、
認証機構を突破したり、javascript で動的に出力されるコンテンツの取得がめんどうだったのと
対象の Web ページが限られていたことから Chrome で要素をエクスポートし、それを加工する方針としました。

当初の目論見

職場で、グループウェアで管理している社内帳票のドキュメント名と管理者、更新日時を
CSV 形式のファイルに落としたい状況となりました。

グループウェアは、Desknet's neo を利用しており、技術スタックは HTML5 + jquery ベースです。

当初の目論見では、URL を指定しあらかじめ決められたルールに従って対象画面のタグを解析し
CSV 形式に適宜加工するスクリプトを想定していました。

挫折、そして妥協

しかし、Desknet's の認証機構を突破し、javascript イベントを発火させて目的のコンテンツを表示させるのは
使い捨てのスクリプトとしては骨が折れました。

そこで、HTML の取得は手動ですることにしました。
幸い、Chrome の「要素の検証」機能により、javascript による動的コンテンツが出力する HTML を参照することができます。
それをバッファにコピーして、テキストエディタに貼り付ければ、望みの生 HTML が手に入ります。ダサいですがとりま妥協。

元データは以下のような形式です。

source.html
<table>
<tbody class="co-tbody-list ui-draggable" aria-disabled="false">
  <tr class="doc-listmod ">
    <td class="co-thd-handle"><span class="co-draghandle">:</span></td>
    <td class="co-chk"><input type="checkbox" name="id" value="5527"><input type="hidden" class="jco-id" value="5527"></td>
    <td class="doc-list-name jco-listview-widauto" style="width: 282px;"><a href="#cmd=docmsetrefer&amp;id=5527&amp;folder=134" class="jco-dragname" title="&nbsp;(総-XXX)捺印簿">&nbsp;(総-XXX)捺印簿</a></td>
    <td class="doc-list-entry"><span title="田中 理央">田中 理央</span></td>
    <td class="doc-th-ymdhi-his" style="width: 143.5px;"><a href="#cmd=docmsetrevindex&amp;id=5527&amp;folder=134">2013/01/02 12:21</a></td>
  </tr>

  <tr class="doc-listmod ">
    <td class="co-thd-handle"><span class="co-draghandle">:</span></td>
    <td class="co-chk"><input type="checkbox" name="id" value="4614"><input type="hidden" class="jco-id" value="4614"></td>
    <td class="doc-list-name jco-listview-widauto"><a href="#cmd=docmsetrefer&amp;id=4614&amp;folder=134" class="jco-dragname" title="(総-XXX)社員情報(新規・変更)登録届">(総-XXX)社員情報(新規・変更)登録届</a></td>
    <td class="doc-list-entry"><span title="山田 太一">山田 太一</span></td>
    <td class="doc-th-ymdhi-his"><a href="#cmd=docmsetrevindex&amp;id=4614&amp;folder=134">2016/02/03 16:42</a></td>
  </tr>
</tbody>
</table>

最終型

結果的に以下のコードに落ち着きました。

getList.js
var client = require('cheerio');
var fs = require('fs');
var file = process.argv[2];

fs.readFile(file, function (err, contents) {
  $ = client.load(contents.toString());
  var result = [];
  $('tr').each(function(i, tr){
    var row = {};
    $(tr).children().each(function(j, td){
      if($(td).hasClass('doc-list-name')){
          row.docname = $(td).text();
      } else if($(td).hasClass('doc-list-entry')){
          row.owner = $(td).text();
      } else if($(td).hasClass('doc-th-ymdhi-his')){
          row.ymdhi = $(td).text();
      }
    });
    if (Object.keys(row).length != 0){
      result.push(row);
    }
  });
  result.forEach( function (h) {
    console.log(`"${h.docname}","${h.owner}","${h.ymdhi}"`);
  });
});

取得した HTML を解析し、加工するのは cheerio モジュールを使用しました。
cheerio は jquery ライクなセレクターの機能が利用でき、コードをシンプルに記述することができます。

前述の HTML に対する出力結果は以下のとおりです。

" (総-XXX)捺印簿","田中 理央","2013/01/02 12:21"
"(総-XXX)社員情報(新規・変更)登録届","山田 太一","2016/02/03 16:42"

終わりに

一昔前、テキスト加工といえば Ruby や Perl, Python に bash が定番でした。
しかしながら、マークアップ言語の加工は、XPath や xml ライブラリを使いこなす必要があり、煩雑になりがち。
Node.js のおかげで、コマンドライン上で jquery の強力なパース機能をつかえるのは嬉しいです。

私のプログラミング上の母語は Ruby なのですが、
javascript の無名関数は、Ruby のブロックとよく似た概念で、私の思考と親和性が高いです。
今後は積極的に node.js で実装していきたいと思います。

4
4
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
4
4