Capybara+PhantomJSでCSVをダウンロード

  • 8
    いいね
  • 0
    コメント

フォームやリンクからCSVをダウンロードしたい場合があるかと思いますが、PhantomJSが現行バージョンではContent-Dispositionで返ってきたレスポンスを受け取ってくれません。

https://github.com/ariya/phantomjs/issues/10052

とはいえ、どうしてもファイルを受け取りたい場合があったので、結構強引だけど実装してみた(実際に書いたコードは複雑なので、エッセンス部分だけ)。

まず「クリックしたいボタンのPOSTをAjaxでエミュレートして結果コンテンツを戻す関数」をJavaScriptで書き、定義をぶっ込む。

page.execute_script(%!
  window.getCsv = function(target){
    var efn = document.querySelector("input[value='"+target+"']");
    if (efn) {
      var f = efn.parentNode;
      var es = f.getElementsByTagName("input");
      var query_str = "";
      for (var i=0; i<es.length; i++) {
        var name = es[i].getAttribute('name');
        var val  = es[i].getAttribute('value');
        if (name) {
          query_str += name + '=' + val + '&';
        }
      }
      var xhr = new XMLHttpRequest();
      xhr.open(f.getAttribute('method'), f.getAttribute('action'), false);
      xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
      xhr.send(query_str);
      return xhr.responseText;
    }else{
      return "";
    }
  }
!)

関数の中身は、適当に。対象ページによって全然変わってくるだろうし、jQueryなどをインジェクトしてあればもっと簡単に書けるはず。

そして、必要な場面でCSVを取り出す。

ret = page.evaluate_script("getCsv('#{target}')")
ret.split("¥r¥n").each do |line|
  # do something
end

RubyとJavaScriptが錯綜して少しトリッキーだけど、基本的には認証やCSRF対策が施されたページでも動くはず。