2012年4月1日日曜日

jsdomが「possible EventEmitter memory leak detected」とか言うので、かわりにcheerioを使ったら解決した。

nodeでwebスクレイパーを作りたかったので、
下のサイトを参考にjsdomを使って、作ってみた。
http://sakuratan.biz/archives/3393

cookieとかにも対応したいので、httpじゃなくてrequest、
お、jqueryで操作できるとかアツイじゃん、ってことでjsdomを使ってた。

https://github.com/tmpvar/jsdom
https://github.com/mikeal/request


で、jsdomでjqueryオブジェクト作って操作するあたりで謎なエラーが出た。


(node) warning: possible EventEmitter memory leak detected. 11 listeners added. Use emitter.setMaxListeners() to increase limit. 
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.
^
SyntaxError: Unexpected token <
        $(window).unload(function(){
 ^
ReferenceError: $ is not defined


なのでjsdomのかわりにcheerio使ったら解決したというお話。


1つ目のエラーは、1つのイベントにリスナーをつけすぎると(デフォルトでは11個以上?)でるとか。maxは設定できるけど、jsdomだかrequest内(どっちか忘れた)で発生してたっぽいのでそういう問題じゃないと判断。

2つ目と3つ目はHTMLのパースエラー?(3つ目はjavascript部っぽい。CDATAとかあればだいじょうぶだったのかな。)

んでここで「jsdom eventemitter memory leak」で検索したら、stackoverflowに良い情報を見つけた。

http://stackoverflow.com/questions/5718391/memory-leak-in-node-js-scraper

要約
質問者「jsdomがやたらとメモリリークするんだけどなんとかなんない?」
回答者「jsdomつかってないでcheerio使えよ。捗るぞ。」
で、cheerioを使ってみた。
https://github.com/MatthewMueller/cheerio

readmeの一部を翻訳

What about JSDOM?

jsdomにイライラしたので、cheerioを書きました。以下の3つが、もっともイライラした事項です。
  • JSDOMのパーサーが厳格すぎる。厳格すぎて、最近のサイトに対応できない。
  • JSDOMは遅すぎる。大きいサイトをパースすると、明らかに遅い。
  • JSDOMは重すぎる気がする。JSDOMのゴールは、ブラウザ並のDOM環境を提供することらしい。そんなのはいいから、私はシンプルなHTML操作がしたいだけなのだ。
今回俺がぶち当たった問題は1番。2番、3番はそうなの?って感じだった。


まぁでも実際、かなりシンプルだった。

#!/usr/local/bin/node

var cheerio = require("cheerio");
var request = require("request");

request({url:"http://www.google.com"}, function (error, response, body) {
    if (!error && response.statusCode == 200) {
        $ = cheerio.load(body);
       
        console.log($("title").text());
    }  
});


みたいな感じでjQueryでDOMいじれる。


みたいな感じでjQueryっぽい、cheerioのオブジェクトで、DOMがいじれる。
EDIT:2012/04/10 jQueryオブジェクトじゃなかったです^p^


cheerioに切り替えて以来なんもエラー出てないからきっと大丈夫!