2013年11月30日土曜日

右クリック禁止 ---- nhk みんなのうた

nhk みんなのうたのページで文字を選択して、右クリックから 「Googleで検索」をしようとしたらコンテクストメニューが出ない。firefox の自前のアドオンで、ある程度対策を採ってあるのだが効いていなかった。で、ソースをのぞいてみた。

$(document).bind("contextmenu",function(e){
    return false ;
});

で早速

$(document).unbind("contextmenu");

の対策を追加した。nhk オンラインでは右クリックを禁止していない。どうして「みんなのうた」だけ?

ちなみに僕が見ていたのは「チグエソ地球の空の下で」である。歌もいいが、放映時の映像に昭和のこどもたちを被写体にした土門拳の写真が使われていたことで印象に残っていた。

2013年11月29日金曜日

YQL でクロスドメイン HTML、JSON 取得・処理をしてみた

ひと月ほど前からクロスドメインで html や json を取得・処理するために json proxy(jsonp.jit.su)を使っていたのだが、jsonp.jit.su が "502 Reached max retries limit" が出て使えなくなった。一時的ならいいのだが復旧まで2~3日かかった。調べてみると以前にも何度かあったようである。個人的に使うだけなのでたいした信頼性は必要ないのだが、3日も使用不能になるのでは見捨てざるを得ない。

ということで代わりに YQL を使ってみた。便利なサービスだが json proxy からの移行でつまずいたところがある。問題は jsonp.jit.su はオリジナルを忠実に返していたのに対し、YQL はかなり整形・改変して返すのである。

html の処理ではオリジナルのソースを見て必要部分を正規表現で抽出していたのだが、YQL は <img attr="xxx" class="yyy"> を <img class="yyy" attr="xxx"> のように属性の記述順序を変えてしまう。
また空の要素を削除してしまう。内容の切り出しに使っていた <div class="endbox"></div> があっさりと削除されてしまっていた。

json では不可解な変更を加える。

一つ目は、数字からなるオブジェクトの名前を改変するのである。たとえばオリジナルでは {"12345678":value} となっているものを {"_2345678":value} として返すのである。「おーーーい先頭の '1' はどこに行ったんだよぉーーーー」。この数字はあるデータの識別番号を http リクエストのパラメーターとしてこちらから渡しているものである。不可逆の変更を加えられてはたまったものではない。オブジェクト名が数字で始まってはいけないなんて規則をどこからひねりだしたんだろうか。

さらにオブジェクトの値についても致命的な変更を加える。{string:false} を {string:"false"} に改変するのである。それまで真偽値をチェックしていたところを文字列の比較に変えざるを得なかった。どうやらオブジェクトの値はすべて文字列に変更するようだ。以下に例を挙げる。

[オリジナルのレスポンス]
{"error":false,"status":0,"id":27604170,"title":"no title","duration":3360}

[yql のレスポンス]
{"query":{"count":1,"created":"2013-12-04T02:09:20Z","lang":"ja","results":{"json":{"error":"false","status":"0","id":"27604170","title":"no title","duration":"3360"}}}}

というわけで YQL を使った json 処理は、オリジナルを直接処理するのに比べ、著しく汎用性を欠くものにならざるを得ないのであるが、個人的な利用だから何とかごまかしながら使うことにする。

([追記]json については解決策が見つかった。yql に jsonCompat=new というパラメータを渡せばよい。本家 http://developer.yahoo.com/yql/guide/json_to_json.html にちゃんと書いてあった。ググってコードを流用する簡便さに馴れて泥縄でやっていると往々にしてこういうところに引っかかる。でもやめられない)

最後に ajax を使ったコードの断片を載せておく。


var url = "http://foo.com/bar.html";
$.ajax({
url: yql_make_url(url),
dataType: "text",    // 正規表現で処理するので "html" ではなく "text"
type: "GET",
success: function(data){
    var html = data;
}
});

var url = "http://foo.com/bar.json";
$.ajax({
url: yql_make_url(url, "json", "json"),
dataType: "json",
type: "GET",
success: function(data){
    var json = data;
}
});

function yql_make_url(url, from, to)
{
    if (! from)
        from = "html";
    if (! to)
        to = "xml";
    var q = 'select * from ' + from + ' where url="' + url + '"';
    var yql = "http://query.yahooapis.com/v1/public/yql?q="
                + encodeURIComponent(q)
                + "&format=" + to;
    if (from == "json")
        yql += "&jsonCompat=new";
    return yql;
}