SIMILE

id:brazilさんより。Twitter / 33: @ku XULRunnerでサーバーでスクレイピング ...

SIMILE Project

SIMILE is focused on developing robust, open source tools based on Semantic Web technologies that improve access, management and reuse among digital assets. Learn more about the SIMILE project.

なんかpiggy bankっていうSITEINFOににたようなのがあって、それを生成するためのGUIフロントエンドのSolventというのと、SITEINFOみたいなやつを使ってデータを抽出するCrowbarっていうのとがある。
jsのコードでスクレイピングをするっぽくてあんまりいただけない。CrowbarはXULRunnerで動いてHTTPのAPIでリクエストを投げるとXMLでデータを返してくれる。XULRunnerを選択した理由はFirefoxと厳密に同じDOM/XPathを利用したいから。なんでFirefoxと厳密に同じなのがいいかというとGUIフロントエンドのSolventがFirefox extensionだから。DapperのMozilla Java Html ParserのようにXPCOM経由でC++で努力する価値がないときにはXULRunnerはちょーべんりだ。

CrowbarでHTMLのエレメントを選択すると、そのエレメントを表すXPathを生成してくれるんだけどそのXPathがちゃんと無駄にstrictじゃないやつを生成する。その部分のコードを読む。


どうでもいいけどたぶんSolventは直接window.content触ってる。読み取るだけだからまたjavascriptのセキュリティ - ゼロメムはてな支店からすると危なくないのかもしれないけどよくわかんない。


なんかsolventのコード素人くさい。MITの人が書いたのだろうか。
trとtdがなんで特別扱いなのか分かんないし、その書き方もひどい。cellsとrowsが違うだけならそこだけ外に出せばいいのに。

Capture._captureNode = function(node) {
    var xpath = "";

    var namespace = node.ownerDocument.documentElement.namespaceURI;
    var prefix = namespace ? "x:" : "";

    var node2 = node;
    var doc = Capture._currentDoc;
    while (node2 && node2 != doc) {
        var tag = node2.tagName.toLowerCase();
        var id = node2.id;
        var className = node2.className;

        var segment = prefix + tag;
        if (tag == "tr") {
            var rowCount = node2.parentNode.rows.length;
            if (rowCount > 1 && rowCount < 5) {
                segment += '[' + (node2.rowIndex+1) + ']';
            }
        } else if (tag == "td") {
            var cellCount = node2.parentNode.cells.length;
            if (cellCount > 1 && cellCount < 5) {
                segment += '[' + (node2.cellIndex+1) + ']';
            }
        }

        if (className && className != "") {
            var classes = className.split(" ");
            var newClasses = [];
            for (var c = 0; c < classes.length; c++) {
                var cl = classes[c];
                if (cl.indexOf("simile-solvent-") < 0) {
                    newClasses.push(cl);
                }
            }
            if (newClasses.length > 0) {
                segment += '[@class="' + newClasses.join(" ") + '"]';
            }
        }

        if (id && id != "") {
            xpath = "//" + segment + '[@id="' + id + '"]' + xpath;
            break;
        }

        xpath = "/" + segment + xpath;

        node2 = node2.parentNode;
    }

ふつうのことをなんかへんな方法でやってそうなのが分かっただけだった。
セマンティックとかのひとはあんまりコード書くのはうまくないんだろうか。