ネオおとなり日記というものをつくりました(greasemonkey)

なにこれ?

はてなダイアリーには、おとなり日記という機能がありますが2週間経つと消えたり、どういう仕組みか気になったのでgreasemonkeyを使って新たにつくることにしました。

どういうの?

本家おとなり日記はエントリーに含まれる全てのキーワードの一致数をもとにおとなりさん度を評価しているようですが、ネオおとなり日記はエントリー中に含まれるキーワードをランダムに3つ選んでgoogleに投げた結果を表示します。おとなりさん度の評価はgoogle任せです。
当初はキーワードをひとつずつgoogleに投げてヒット数をもとに、ホットなキーワードを厳選して、またそれをgoogleになげて評価しようとしてましたが、怒られたり、疑問を感じたので現在の形になりました。

キーワードをランダムに選んでいるので、おみくじ的要素があっておもしろい結果が得られるとおもいます。もともと嗜好の合うおとなりさんを見つけてお友達になるきっかけになればと思ってつくりました。

demo

インターネットの広告が話題になっているようなので便乗してみたのページで実行した例をお見せします。

本家の下にネオおとなり日記が表示されています。このエントリーのキーワードは "スクリプト", "greasemonkey", "japan", "アドレスバー", "コピペ", "ソースコード", "人気の記事", "javascript", "cnet"で、その中から"greasemonkey","japan","javascript"を選び、おとなりさんを探しています。自分のダイアリーがおとなりさんとして検出された場合は「なし」と表示してあります(改良の余地あり)。

使う前に

  • 自分のダイアリーの 管理 -> 設定 -> 記事の設定 ->「キーワードの自動リンク設定」にあるスコアの値を上げると、キーワードが絞られておとなりさん度を高めることができます。お好みでどうぞ。
  • ネオおとなり日記が表示されるのは、個別のエントリーのページです。自分のダイアリー、他人のダイアリーでも表示されます。

インストール

firefoxのアドオンであるgreasemonkeyをインストールしたのち、下記のhatena_neo_otonari_diary.user.jsをクリックしてインストールしてください。
hatena_neo_otonari_diary.user.js

ソースコード

// ==UserScript==
// @name           hatena_neo_otonari_diary
// @namespace      http://d.hatena.ne.jp/Cherenkov/
// @include        http://d.hatena.ne.jp/*
// ==/UserScript==


(function(){

    //キーワードの重複を防ぐ
    Array.prototype.contains = function( value ){
        for(var i in this){
            if( this.hasOwnProperty(i) && this[i] === value){
                return true;
            }
        }
        return false;
    }

    //キーワードをシャッフルする
    Array.prototype.shuffle = function() {
        var i = this.length;
        while(i){
            var j = Math.floor(Math.random()*i);
            var t = this[--i];
            this[i] = this[j];
            this[j] = t;
        }
        return this;
    }


//ネオおとなり日記の土台を築く
function baseNeo(){

    var refererlist = document.createElement('div');
    refererlist.setAttribute('class','refererlist');
    var caption = document.createElement('div');
    var acaption = document.createElement('a');
    acaption.href = ghref;

    caption.setAttribute('class','caption');
    acaption.appendChild(document.createTextNode('ネオおとなり日記'));
    caption.appendChild(acaption);
    caption.appendChild(document.createTextNode(' : '+main_query));

    refererlist.appendChild(caption);
    var ul = document.createElement('ul');
    ul.id = 'neoOtonari';
    refererlist.appendChild(ul);

    day.snapshotItem(0).appendChild(refererlist);

}


//エントリーからキーワードを取得して、シャッフルして3つ選ぶ
function getMainQuery(){

    var keyword = [];

    for(var i=0;i<kw.snapshotLength;i++){
        if(!keyword.contains(kw.snapshotItem(i).textContent))
        keyword.push(kw.snapshotItem(i).textContent);
    }
    
    //add sectioncategory to keyword.
    var category = document.evaluate('//a[@class="sectioncategory"]', document, null, 7, null);
    for(var i=0;i<category.snapshotLength;i++){
        if(!keyword.contains(category.snapshotItem(i).textContent))
        keyword.push(category.snapshotItem(i).textContent);
    }


    keyword.shuffle();
    console.log(keyword);


    var mainq = [];
    for(var i=0;i<3;i++){ mainq.push(keyword.shift());}
    
    console.log(mainq);
    
    return mainq = mainq.join(' ');

}


//googleの検索結果のページからおとなりさん情報を抽出して表示する
function getOtonariInfo(res){

    var otonari = {};

    for(var i=0;i<10;i++){

        otonari.time = /<font size=-1 color=#666666>(.+?)<\/font>/g.exec(res.responseText)[1]
        otonari.url = /<h3 class=r><a href="(.+?)"/g.exec(res.responseText)[1];
        otonari.title = /class=l onmousedown.+?">(.+?)<\/a>/g.exec(res.responseText)[1];
            otonari.title = otonari.title.replace(/<em>|<\/em>|<b>|<\/b>/g,'');


        console.log(otonari.time);
        console.log(otonari.url);
        console.log(otonari.title);



        var m = location.href.match(/http:\/\/(.+?)\/(.+?)\//);
        var mydiary = m[1]+'/'+m[2];
        var ul = document.getElementById('neoOtonari');

        if(!otonari.url.match(mydiary) && !otonari.url.match(/d.hatena.ne.jp\/keyword|d.hatena.ne.jp\/hotkeyword/)){
             var li = document.createElement('li');
             li.appendChild(document.createTextNode(otonari.time+' '));
             ul.appendChild(li);
             var ali = document.createElement('a');
             ali.href = otonari.url;
             ali.appendChild(document.createTextNode(otonari.title));
             ali.rel = 'nofollow';
             li.appendChild(ali);
        }else{
        
             var li = document.createElement('li');
             li.appendChild(document.createTextNode('なし'));
             ul.appendChild(li);
        
        }

    }
}



var day = document.evaluate('//div[@class="day"]', document, null, 7, null);
var kw = document.evaluate('//a[@class="keyword"]', document, null, 7, null);

//キーワードが1個以上ある個別のエントリーのページで実行する
if (day.snapshotLength == 1 && !kw.snapshotLength == 0){

    var main_query = getMainQuery();

    var option = ' -hsada -searchdiary -keywordword&as_sitesearch=d.hatena.ne.jp&as_qdr=m&num=10';
    var ghref = 'http://www.google.co.jp/search?as_q=' + encodeURI(main_query) + option;


    baseNeo();


    GM_xmlhttpRequest({
        method:"GET",
        url: ghref,
        headers:{"User-Agent":"Mozilla/5.0","Accept":"text/xml"},
        onload:function(res) {

            getOtonariInfo(res);

            }

        });
}

})();

気になるとこ解説

  • キーワードを3つに選ぶのは適当。
  • エントリーのカテゴリの項目もキーワードに追加している。わりと重要だとおもったので。
  • 10件のおとなりさんを表示することになっている(getOtonariInfo関数で)。減ったらそのまま。
  • getOtonariInfo関数でgoogleに投げているoptionは結果をみてころころ編集。改良の余地あり?
  • ネオおとなり日記と書かれた部分は、googleに投げたものを参照できるリンクがついている。その横に選ばれた3つのキーワードを表示している。

今後のネオおとなり日記

  • 選択からはずれたキーワードをgoogleのOR検索にまわせば、さらにおとなりさん度を高めることができるかもしれない。
  • googleブログ検索で探したらどうか検討。
  • 検索結果が一件もないときなにもでない仕様をどうにかする。

感想

引数の使い方覚えたてで無理やり関数化を図ってみた。適切かどうかはよくわからない。教えてください。
このスクリプトをきっかけに友達の輪が広がればいいな。ご意見ご感想お待ちしています。