2012.08.21 | 

///
このメモのブックマークレットはうごかなくなりました。
新しいバージョンのメモはこちら
URLに対するフェイスブックのいいね数を調べるツール。その3
///

どうも。kaminalyです。
以前、「URLに対するフェイスブックのいいね数を調べるツール。
をメモったんですが、
それを改良したので、またメモっていますよ。

ブックマークレットの意味がよくわからず、
このツールを堪能できていない人も多いようですね。。。
このツールは「いいねどんだけ〜」のリンク部分を右クリックしてブックマークに保存したり、
ブックマークバーにリンクをドラックしてブックマークしたりしておいて、
いいね数を調べたいサイトをブラウザで開いた状態で、
保存しておいたブックマークを押す(開く)とアラートでお知らせするというものです。

ではどうぞ。

いいねどんだけ〜Ver2(超他力本願バージョン)

こちらは、@hidekiyさんのプロキシ
海外のシェアカウントサービスのsharedcount.com
@dankogaiさんのxhrの実装をマッシュアップして作りました。
せっかくjQurey.ajaxからxhrにしたのに、IEでの挙動があやしいので、
ChromeやFirefoxなどで使うのをお勧めします。

アラートにerrorと出ることがありますが、
ページの取得に失敗したときに出るものです。
何度試してもerrorになる場合は・・・あきらめてください(汗

興味ある人は続きの開発メモもご覧下さい。

以前のやつは、いいねのトータルの数値で、
本当はshereとlikeとコメントに分けられるみたいなので、
詳細な情報に分けるというのと、ツイッターとググタスとはてブを追加しようと思って、
作業に取りかかりました。

実装はさらっと終わりました。
こんな感じ。


//bookmarklet
javascript:(
	function(){
		var s=document.createElement('script');
		s.type='text/javascript';
		s.onload=b;
		s.src='https://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js';
		document.body.appendChild(s);

		function b(){
			var $=jQuery.noConflict(true),u=encodeURIComponent(location.href);
			//facebook
			$.get('https://api.facebook.com/method/fql.query?query=select%20like_count,%20share_count,%20total_count%20from%20link_stat%20where%20url%3D%22'+u+'%22', function(d){
				var fl = $(d).find('like_count').text(),
				fs = $(d).find('share_count').text(),
				ft = $(d).find('total_count').text(),
				fc = ft - fl - fs;
				//twitter
				$.get('http://cdn.api.twitter.com/1/urls/count.json?url='+u, function(d){
					var tt = d.count;
					//google+
					$.get('https://plusone.google.com/u/0/_/+1/fastbutton?count=true&url='+u, function(d){
						var gp = $(d).find('#aggregateCount').text();
						//はてブ
						$.get('http://api.b.st-hatena.com/entry.count?url='+u, function(d){
							var hb = d == '' ? 0 : d;
							alert('Facebook\n-Like: ' + fl + '\n-Share: ' + fs + '\n-Comment: ' + fc + '\n-Total: ' + ft + '\nTwitter\n-Tweet: ' + tt + '\nGoogle+\n-+1: ' + gp + '\nHatena\n-bookmark: ' + hb);
						});
					});
				});
			});
		}
	}
)();

で、テストしてみると・・・
エラー。

ほにゃ?

よくよく考えてみたら、クロスドメインじゃね?
なんで、Facebookだけの時は上手く動いたんだろ?
で、調べるとすぐに、
ヘッダ情報のAccess-Control-Allow-Originの存在を知ることになりました。
この情報の値を、許可するホスト名か、*にしてあげると、
XMLHttpRequest Level 2からクロスドメインでajaxできるそうです。
その際、IEでは独自実装のXDomainRequestを使えば
IE8以降で同じくクロスドメインでajaxできるそうです。

なるほど。

ヘッダ情報を追加するためのプロキシはphpなりなんなりですぐに用意できます。
例えば、


<?php
	//cross domain ajax proxy
	header("Access-Control-Allow-Origin: *");
	//今回はPOST, OPTIONSは必要ないけどテンプレート的に付けている。OPTIONSはfirefox対策
	header("Access-Control-Allow-Methods: GET, POST, OPTIONS");
	//IE8 fix
	header("Access-Control-Allow-Headers: *");

	//適宜
	header("Content-Type: text/plain; charset=UTF-8");

	//どこかしらのurlからデータをゲットしてそのまま出力
	if($_GET["url"]){
		$url = rawurlencode($_GET["url"]);
		$facebook = file_get_contents("https://api.facebook.com/method/fql.query?query=select%20like_count,%20share_count,%20total_count%20from%20link_stat%20where%20url%3D%22".$url."%22");
		$twitter = file_get_contents("http://cdn.api.twitter.com/1/urls/count.json?url=".$url);
		$google = file_get_contents("https://plusone.google.com/u/0/_/+1/fastbutton?count=true&amp;url=".$url);
		$hatena = file_get_contents("http://api.b.st-hatena.com/entry.count?url=".$url);
	}

	print <<<__HD__
<data>
	{$facebook}
	<twitter>{$twitter}</twitter>
	{$google}
	<hatena>{$hatena}</hatena>
</data>
__HD__;

上記のプロキシを使うなら、こんなjsを用意すれば動く。
「プロキシのURL」は設置した場所に書き換える。
IE対策のためにjQuery.ajaxからxhrに実装をかえてあります。


//bookmarklet
javascript:(
	function(){
		var s=document.createElement('script');
		s.type='text/javascript';
		s.onload=b;
		s.src='https://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js';
		document.body.appendChild(s);

		function b(){
			var $=jQuery.noConflict(true),
			u='プロキシのURL.php?url='+encodeURIComponent(location.href),
			c=function(d){
				var jq = $(d),
				fl = jq.find('like_count').text(),
				fs = jq.find('share_count').text(),
				ft = jq.find('total_count').text(),
				fc = ft - fl - fs,
				tt = eval('(' + jq.find('twitter').text() + '.count)'),
				gp = jq.find('#aggregateCount').text(),
				hb = jq.find('hatena').text();
				hb = hb == '' ? 0 : hb;
				alert('Facebook\n  Like: ' + fl + '\n  Share: ' + fs + '\n  Comment: ' + fc + '\n  Total: ' + ft + '\n\nTwitter\n  Tweet: ' + tt + '\n\nGoogle+\n  +1: ' + gp + '\n\nHatena\n  bookmark: ' + hb);
			},
			x;
			if (window.XDomainRequest){
				u.replace('https', 'http');
				x = new XDomainRequest();
				x.onload = function(){ c(x.responseText); };
				x.open('GET', u);
			}else{
				x = new XMLHttpRequest();
				x.onreadystatechange = function(){
					if (x.readyState === 4) c(x.responseText);
				};
				x.open('GET', u, true);
			}
			x.send();
		}
	}
)();

とここまで進んだところで、
設置するSSLないな。。。(本当はあるんだけど、サーバ共有でなんかハズい)
httpsに置いておかないと、https付きのサイトで使えない。
むむむ。

ボロボロの精神状態でウェブを彷徨っていると、
allow-any-origin.appspot.comにたどり着いた。
これは!上記のヘッダ情報を付けてくれるプロキシ!しかもSSLに対応!
神、神が現れたのか?

書き換えたのがこちら。
IEのXDomainRequestがhttpsだと上手く動かない。
しらべると、httpでないとダメっぽい。
httpのサイトだったらhttp、httpsのサイトだったらhttpsに合わせるというような
記事も見かけてやってみたけどダメだった。
この時点で、IEではIE8以降でなおかつhttpのサイトでしか動きません。になる。


//bookmarklet
javascript:(
	function(){
		var s=document.createElement('script');
		s.type='text/javascript';
		s.onload=b;
		s.src='https://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js';
		document.body.appendChild(s);

		function b(){
			var $=jQuery.noConflict(true),
			u=encodeURIComponent(location.href),
			p='http'+(window.XDomainRequest &amp;&amp; u.substr(0,5) != 'https' ? '' : 's' )+'://allow-any-origin.appspot.com/';
			//facebook
			xhr(p+'https://api.facebook.com/method/fql.query?query=select%20like_count,%20share_count,%20total_count%20from%20link_stat%20where%20url%3D%22'+u+'%22', function(d){
				var jq = $(d);
				fl = jq.find('like_count').text(),
				fs = jq.find('share_count').text(),
				ft = jq.find('total_count').text(),
				fc = ft - fl - fs;
				//twitter
				xhr(p+'http://cdn.api.twitter.com/1/urls/count.json?url='+u, function(d){
					var tt = eval('(' + d + '.count)');
					//google+
					xhr(p+'https://plusone.google.com/u/0/_/+1/fastbutton?count=true&amp;url='+u, function(d){
						var gp = $(d).find('#aggregateCount').text();
						//はてブ
						xhr(p+'http://api.b.st-hatena.com/entry.count?url='+u, function(d){
							var hb = d == '' ? 0 : d;
							alert('Facebook\n  Like: ' + fl + '\n  Share: ' + fs + '\n  Comment: ' + fc + '\n  Total: ' + ft + '\n\nTwitter\n  Tweet: ' + tt + '\n\nGoogle+\n  +1: ' + gp + '\n\nHatena\n  bookmark: ' + hb);
						});
					});
				});
			});

			function xhr(u,c){
				var x;
				if (window.XDomainRequest){
					x = new XDomainRequest();
					x.onload = function(){ c(x.responseText); };
					x.open('GET', u);
				}else{
					x = new XMLHttpRequest();
					x.onreadystatechange = function(){
						if (x.readyState === 4) c(x.responseText);
					};
					x.open('GET', u, true);
				}
				x.send();
			}

		}
	}
)();

Ver1はIE全く動かなかった(チェックすらしてなかった汗)から、
今回はIEも対応しようと思っていたのに残念な空気がながれだす。

1回調べるのにプロキシに4回もリクエストするのもなんか申し訳なくなってきた。
で、いいねの情報を分割できる事を知ったサービスでもある、
sharedcount.comからデータをパクってとマッシュアップしよう。
そうしよう。

最終的なソースはこちら。
sharedcount.comからのデータを整形したのと、
はてブがなかったので足したのと、
ロードが長くなってしまったので、「Now Loading...」の表示を足した。
あと、403エラーが出る事があったので、errorアラートを出すようにした。


//bookmarklet
javascript:(
	function(){
		var s=document.createElement('script');
		s.type='text/javascript';
		s.onload=b;
		s.src='https://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js';
		document.body.appendChild(s);

		function b(){
			var $=jQuery.noConflict(true),
			u=encodeURIComponent(location.href),
			p='http'+(window.XDomainRequest &amp;&amp; u.substr(0,5) != 'https' ? '' : 's' )+'://allow-any-origin.appspot.com/',
			l=$('

Now Loading...

').css({position:'absolute',zIndex:10000,textAlign:'center',fontSize:'20px',backgroundColor:'#990',color:'#fff',margin:'0',padding:'30px 0',width:'100%',top:$('body').scrollTop()+'px'}).prependTo('body');
			//sharedcount.com
			xhr(p+'http://sharedcount.com/?url='+u, function(d){
				var s = $(d).find('#stats').html().replace(/\n/g,'').replace(/<!--([^>]|[^-][^-]>)*-->/g,'').replace(/<\/?h3>/g,'\n').replace(/<br[^>]*>/g,'\n');
				//はてブ
				xhr(p+'http://api.b.st-hatena.com/entry.count?url='+u, function(d){
					var h = d == '' ? 0 : d;
					l.remove();
					alert(s + '\nHatena\nbookmarks: ' + h);
				});
			});

			function xhr(u,c){
				var x;
				if (window.XDomainRequest){
					x = new XDomainRequest();
					x.onload = function(){ c(x.responseText); };
					x.onerror = function(){
						l.remove();
						alert('error');
					};
					x.open('GET', u);
				}else{
					x = new XMLHttpRequest();
					x.onreadystatechange = function(){
						if (x.readyState === 4){
							if(x.status == 200){
								c(x.responseText);
							}else{
								l.remove();
								alert('error');
							}
						}
					};
					x.open('GET', u, true);
				}
				x.send();
			}
		}
	}
)();

かなり遠回りをして、
最終的に完全に他力本願ツールになってしまった。
IE8以降でhttpは対応のはずだったんだけど、IE8でなぜか動かなかった。
もしかしたら、IE8fixのヘッダが入ってないのかも。
まぁ、IEは非対応と言い切ってしまったほうが安全なのである。