Ruby
Capybara
PhantomJS

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

More than 1 year has passed since last update.

フォームやリンクから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対策が施されたページでも動くはず。