読者です 読者をやめる 読者になる 読者になる

Chrome拡張機能でFileSystemAPIを使ってみた

Google Chrome

ブラウザからDOMを解析してローカルファイルへ保存する方法がないかを調査したときのメモ。


2013/01/19 追記
2013/01/19時点のChrome 24.0.1312.52 m において、以下の情報は古い上、ソースコードは動作しません。
続編的なものは以下の記事となります。
Chrome24 + Manifest v2 にて、Chrome拡張機能 + FileSystemAPI を使ってみた - メモ的な思考的な
2013/01/19 追記 ここまで


■ブラウザごとのローカルファイル保存方法
ブラウザ別の実際のコードは、以下のサイトが詳しい。

あらびき日記 - JavaScriptからローカルファイルを作成する方法まとめ


HTML5を押さえておきたいと思っていた矢先、
ChromeではHTML5のFileAPI:Writerを使っているとのことなので、Chromeを選択。
なお、Chrome16では起動オプションをつけなくても、FileAPI:Writerは使える模様。


Chrome 拡張機能の作り方
大きな流れとしては、以下を参考に。
Playground of Mine - Chrome Extensions - Content Script


■作成の概要
1.動作
指定されたURLをChromeで開いたときの流れは以下。

  1. コンテント・スクリプトが感知
  2. コンテント・スクリプトがDOMを解析
  3. コンテント・スクリプトからバックグラウンド・ページへデータを送信
  4. バッググラウンド・ページにて、FileAPI:Writerでローカルファイル書込み


2.今回、自分で用意したもの

  設定を行うところ

  • contentscript.js

  コンテント・スクリプト

  • background.html

  バックグラウンド・ページ用


■実際のコード
今回は、W3CのサイトからタイトルとURLを取得し、ローカルに保存するコード例。

{
  "name": "File Writer Sample",
  "version": "1",
  "background_page": "background.html",
  "content_scripts": [
    {
      "matches": [
        "http://www.w3.org/"
      ],
      "js": [
        "contentscript.js"
      ]
    }
  ]
}
  • contentscript.js
//  DOM解析
var title = document.getElementsByTagName("TITLE").item(0).firstChild.nodeValue;
//  URL取得
var url = location.href;

//  JSON形式で戻り値を指定する
chrome.extension.sendRequest({"siteTitle": title,
                              "siteUrl": url
                             });
  • background.html
<html xmlns="http://www.w3.org/1999/xhtml1">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  </head>

  <body>
    <script>
      //  ダウンロード時の日本語文字化けを防ぐため、headタグにて文字コードを「utf-8」指定しておく

      chrome.extension.onRequest.addListener(function(request, sender, sendResponse){
        var errorCallback = function(e){};

        /*
          現状では、[000000]ファイルが存在していないと、エラーとなってしまう
          0バイトでもよいので、所定の位置にファイルを保管しておくこと
        */
        
        webkitRequestFileSystem(TEMPORARY, 1024*1024, function(fileSystem){
          fileSystem.root.getFile("testfile.txt", {'create':true}, function(fileEntry){
            fileEntry.createWriter(function(fileWriter){
            
              //  ファイルの書き込み位置は、一番最後とする
              fileWriter.seek(fileWriter.length);

              var blobBuilder = new WebKitBlobBuilder();

              //  0バイトファイルの場合、ヘッダ行を作成する
              if (fileWriter.length == 0)
              {
                var headers = new Array(addQuote("サイトタイトル"),
                                        addQuote("URL"));
                var header = headers.join(",");
                blobBuilder.append(header);
                
                blobBuilder.append("\n");  //  ヘッダの終わりは改行
              }

              //  データ行の作成
              var details = new Array(addQuote(request.siteTitle),
                                      addQuote(request.siteUrl));

              blobBuilder.append(details.join(','));
              blobBuilder.append("\n");  //  データの終わりは改行

              fileWriter.onerror = function(e){
                alert("write failed : "+e);
              };

              fileWriter.write(blobBuilder.getBlob("text/plain"));
            }, errorCallback);
          }, errorCallback);
        }, errorCallback);
      });


      /*
        CSVファイル用に、項目をダブルクオートで囲む
      */
      function addQuote(field)
      {
        return  "\"" + field + "\"";
      }

    </script>
  </body>
</html>


■ファイルの保存先
%USERPROFILE%\AppData\Local\Google\Chrome\User Data\Default\File System


この中の、「00000000」というファイルを「.csv」付でリネームすれば、CSVファイルが手に入る。
今回の場合、
%USERPROFILE%\AppData\Local\Google\Chrome\User Data\Default\File System\002\t\00
の中に「00000000」というファイルあり。
(拡張機能を複数作っている環境のため、上記のパスになったかと)


■参考
日本語訳リファレンスがためになりました。


ファイルシステム関連の情報がわかりやすく記載されていました。
os0x - File API: Writer, Directories and System


CSVファイルの定義はこちらを参考にしています。
アルプス登山の玄関口・笠井家 - CSVファイルの一般的書式 (RFC4180 日本語訳)