Perl/CGI研究室 'PERL-LABO'

Perl/CGI研究室 'PERL-LABO' TOPへ
戻る(History.Back)

リンククリックカウンターの研究

研究内容

当サイトでは、多くのサイトがそうであるように、 リンク集ページを用意して、いくつかのサイトさんにリンクさせてもらっています。 さて、このリンク集によって、自分のサイトからリンク先のサイトへ、どれくらいの人が訪問しているのか 調べてみましょう!

詳細

来たカウントはできるけど…

「どのサイトから、どれだけの人が自分のサイトに来てくれたか」は、 既に研究したリファラーカウンターによって知ることができます。 このサイトからはたくさんの人が来てくれているなぁ、とか、このサイトからは 全然人が来てくれないなぁ、といったことが分かってしまいます。 この「来てくれた数」は、多くのサイト管理者が興味をもって、実際に解析をしていると思います。 では、逆の、「自分のサイトから、どのサイトに、どれくらいの人が行っているか」というのは、 知ることができるでしょうか?

どのサイトにどれくらいの人が行っているかということが分かれば、 自分のサイトのリンク集がどれくらいの人に利用されているかが分かります。 これは意外とサイト運営に役立つ情報かもしれません。是非知りたいですね!

方法1: IDでジャンプする

その方法の1つは、次のようなURLを使って、ジャンプするというものです。

gotobyid.cgi?yahoo
gotobyid.cgi?google

これは以前 こちら で研究したものですが、 IDに対応するURLを別で用意しておいて、CGIプログラムを上記のように ?ID 付きで呼び出すと 対応するURLにジャンプするというものです。ジャンプするだけでなくて、ジャンプした回数をファイルに保存します。 ジャンプした回数はこちら

これは、私が最初に考えたクリック回数計測の方法だったんですが、 リンク先URLごとにIDを用意する必要があったりして管理が面倒だったりします。

CGIプログラムによって生成されるリンク集(あるいはディレクトリ型検索エンジン)なら、 自動的に登録されたURL毎にIDを生成して、この方法でクリック数をカウントすることもできますが、 今回の研究では、普通のサイトの普通のリンク集で、どのリンクが何回クリックされたか調査したいのです。 なので、この方法は却下です。

リンクにマウスポインタを合わせたとき、ブラウザのステータス欄に 「http://www.perl-labo.org/cgi/gotobyid.cgi?yahoo」 みたいのが表示されるのも 気持ち悪い感じですよね。

方法2: URLでジャンプする

IDとURLの対応を管理する手間を省くだけなら、難しくありません。 URLを直接CGIプログラムに渡してあげればいいですね。

goto.cgi?http://www.yahoo.co.jp/
goto.cgi?http://www.google.co.jp/

ジャンプした回数はこちら

これなら、IDとURLの対応を用意する必要が無いので、ウェブページの中で 他のサイトにリンクするときに、例えば /goto.cgi? を付けるだけで済んだりします。 リンクにマウスポインタを合わせたとき、ブラウザのステータス欄に 「http://www.perl-labo.org/goto.cgi?http://www.yahoo.co.jp/」 みたいのが表示されるのが 気持ち悪いのですが、簡単にクリック数をカウントできるという点では、まあまあのやり方です。

さて、私、最初はこの方法を使ってリンクのクリック回数をカウントしようかなぁと思ったのですが・・・、 さらにいろいろ考えてみまして、実は、いい方法を思いつきました!!それが「次の方法3」です。

方法3: JavaScriptでカウントする

私が思いついたいい方法、それは「JavaScriptで同期通信をしてカウントする」です。 これ、本当にとってもいい方法なんです。 すごく簡単に、リンクのクリック回数をカウントすることができます。 リンクするときに、CGIプログラムを挟むということをしません。 普段と同じように、Aタグを使って直接リンクをするだけで、自動的にそのリンクのクリック回数が カウントされるという魔法のような方法なのです。

この方法が、今回の研究のテーマです。 完成すると、とっても便利で簡単な方法なのですが、完成まではそこそこ大変です。 ここから、じっくり研究していきます。

研究過程

処理の流れ

JavaScriptとCGIプログラムによって、次のような処理を行います。

 1. リンクがクリックされたらJavaScriptの関数が実行されるように全てのリンクのonclickハンドラを設定する。
 2. リンクがクリックされてJavaScriptの関数が実行されたら、
   2-1. クリックされたリンクのリンク先URLを取得して、
   2-2. あらかじめ用意しておいたCGIプログラムを ?URL 付きで呼び出してカウントし、
   2-3. そのリンク先ページを開く。
 3. CGIプログラム側では、渡されたURLのクリック回数をカウントし、記録します。
CGIプログラムでやること

CGIプログラム側では、上記の方法2のような形でURLを渡されたときに、 そのURLのクリック回数をカウントするという処理を行います。 これは、これまでに作ったカウンター類と同じような動作ですし、すでに作った counters.pl ライブラリを使えば 簡単にできます。なので、今回はCGIプログラムについては説明は省略です。 今回の研究は、CGIプログラムの研究というよりもJavaScriptの研究ですね。

クリックしたときにJavaScriptを実行する

JavaScriptというのはPerlと似たようなスクリプト言語で、 HTMLソースの中に埋め込んでおくとブラウザがその内容を実行してくれるというものです。 ここまでは、document.write くらいしか使ってきませんでしたが、 JavaScriptではもっといろんなことができます。

まず、リンクをクリックしたらJavaScriptの関数が実行されるようにするのですが、これは HTMLソースでは次のように書きます。

<script type="text/javascript">
function my_onclick1()
{
	alert("HELLO !");
}
</script>

<a href=#here onclick="my_onclick1()">ここをクリックしてみてください。</a>

ここをクリックしてみてください。(クリックするとjavaScriptが実行されて、HELLO! と表示されます。)

alertというのはメッセージを表示する関数なのですが、ここでは関数が実行された確認のために メッセージを出しています。 onclick="my_onclick1()" というところがミソです。 my_onclick1 というのは関数名ですので、他のものでもOKなのですが、このような形で、 「リンクがクリックされたらJavaScriptの関数を実行する」ということが実現できました。 まずは一歩前進です。

クリックされたリンクのリンク先URLを知る

続いて、クリックされたリンクのリンク先URLを取得しましょう。 これは、次のようにします。

<script type="text/javascript">
function my_onclick2()
{
	var el = document.activeElement;
	var url = el.href;
	alert(url);
}
</script>

<a href=#here onclick="my_onclick2()">ここをクリックしてみてください。</a>

ここをクリックしてみてください。(クリックするとjavaScriptが実行されて、リンク先URLが表示されます。)

JavaScriptの中身ですが、 var el = document.activeElement; というのは、クリックされてアクティブになった 要素(要素と書くとよく分からない感じですが、"リンクそのもの"のことです)をelという変数に入れます。 Perlでは、変数に入れられるのは数値とか文字列とか連想配列への参照とか、そういうものでしたね。 "リンクそのもの" を変数に入れるなんて、なんて摩訶不思議な!と感じますが、 そういうものなんだと思っちゃいましょう。el という変数が、リンクそのものを指しているんです。 で、次の行 var url = el.href; で、リンクのhref、つまりリンク先URLを変数urlに入れます。 この変数 url は、Perlで慣れしたんだ普通の変数ですね。それをalert関数でメッセージ表示しています。

このように、リンク先URLも無事に取得することができました。

URLをCGIスクリプトに渡す

ここが今回の研究の山場の1つ、JavaScriptからCGIプログラムを実行するという部分になります。 リンク先URLが分かったので、count.cgi?http://〜 みたいな形でCGIプログラムを呼び出すことが できれば、CGIプログラム側でカウント処理を行うことができます。

さて、ちょっと横道にそれますが、皆さん、Ajaxというものをご存じでしょうか?このサイトに訪問されるくらいですから、 ご存じの方も多いと思いますが、Ajaxというのは、JavaScriptで、非同期にバックグラウンドでサーバーとのデータ送受信を 行う技術のことをいいます。実はこれが、今回の研究の大きなヒントになったんです。 JavaScriptで非同期通信ができるなら、同期通信だってできるはず。 同期通信ができるなら、リンクがクリックされたとき、リンク先ページを開く前に、 リンク先URLをCGIプログラムに渡すことができるはず!ですよね。

調べてみたら、そのやり方が分かりました。次のような関数を使います。

function wget(url)
{
	// 準備
	var http = null;
	if (window.XMLHttpRequest) {	// Safari, Firefox など
		http = new XMLHttpRequest();
	}
	else if (window.ActiveXObject) {	// IE
		try { http = new ActiveXObject("Msxml2.XMLHTTP"); }	// IE6
		catch (e) {
			try { http = new ActiveXObject("Microsoft.XMLHTTP"); }	// IE5
			catch (e) { return null; }	// Error
		}
	}

	// 同期通信
	http.open("GET", url, false);
	http.send(null);
	return http.responseText;
}

これはJavaScriptの関数で、wget(取得したいウェブページのURL) という形で呼び出すと そのURLにアクセスして、そのウェブページのHTMLソースを文字列として返すというものです。 アクセスが完了してHTMLソースを取得できるまで処理が戻りません。(同期通信です。)

前半の「準備」は、通信をするためのオブジェクトを作っています。 そのオブジェクトはブラウザによって名前が違うため、if〜やtry〜で処理が分かれています。 この部分は、Ajaxの本に載っていたものをそのまま使わせてもらいました。

後半の「同期通信」のところが、実際にウェブアクセスしてHTMLソースを取得するところです。 といっても、通信用オブジェクトが作成できていれば、open、sendという関数を呼ぶだけで 通信ができます。簡単ですね。 (ただし、同じドメイン内のウェブページにしかアクセスできないという制限があります。 この機能を悪用すると、他のサイトに過度の負荷をかけるスクリプトとかが簡単に作れてしまうので、 これは納得の仕様ですね。)

この関数を使って、CGIスクリプトにクリックされたリンクのURLを渡すには、 クリックされたときに実行される関数の中で次のようにするだけです。簡単です!

wget("./gocount.cgi?" + url);
実験してみましょう

それでは、ここまでの研究結果を試してみましょう。 CGIプログラムでは、渡されたURL(QUERY_STRING文字列ですね)をカウントします。 CGIプログラムからの出力は、上記のwget関数によってJavaScript側に渡されますが、 JavaScript側では渡された出力を利用しませんので、CGIプログラムはカウント処理をするだけで 結果を返したりという必要は無いです。"Content-type: text/html\n\n" を出力するだけでいいですね。 LocationでそのURLにジャンプしたりといったことは不要です。

ここでは実験ですから、次のような簡単なカウント処理CGIプログラムを使用します。

#!/usr/bin/perl

require 'hashfile.pl';

$url = $ENV{"QUERY_STRING"};

$countfname = "gocount.txt";
%count = plab::readhashfile($countfname);
$count{$url} = $count{$url} + 1;
plab::writehashfile($countfname, %count);

print "Content-type: text/html\n\n";

hashfile.pl というのは、以前作った連想配列をファイルに読み書きするライブラリです。

JavaScript側は、次のようになります。

<script type="text/javascript">
function wget(url)
{
	// 準備
	var http = null;
	if (window.XMLHttpRequest) {	// Safari, Firefox など
		http = new XMLHttpRequest();
	}
	else if (window.ActiveXObject) {	// IE
		try { http = new ActiveXObject("Msxml2.XMLHTTP"); }	// IE6
		catch (e) {
			try { http = new ActiveXObject("Microsoft.XMLHTTP"); }	// IE5
			catch (e) { return null; }	// Error
		}
	}

	// 同期通信
	http.open("GET", url, false);
	http.send(null);
	return http.responseText;
}
function test()
{
	var el = document.activeElement;
	var url = el.href;
	wget("./gocount.cgi?" + url);
}
</script>

そして、次のようにリンクタグのonclickでJavaScriptの関数を呼び出します。 onclickの他は、普通のリンクですね。

<a href=http://www.yahoo.co.jp/ target=_blank onclick="test()">yahoo</a>
<a href=http://www.google.co.jp/ target=_blank onclick="test()">google</a>

準備はOKです!次のリンクをクリックしてみてください。

 yahoo
 google

ちゃんと、カウントされているかな…?

 ジャンプした回数はこちら

お見事!カウントされています(^^)

でも、onlick を加えるのが面倒…

今までとは全く違ったアプローチで、JavaScript+CGIプログラムでのリンククリック数 カウントの仕組みを作ることができました。(久しぶりに、プログラムするのが楽しかったです^^) これまでの方法(間にCGIプログラムを挟む方法)とは違い、リンク先は通常通りのURLなので、 ブラウザのステータスバーに表示されるリンク先URLもいつも通りで、自然です(上にある、google、yahooのリンクに マウスポイントをあわせて見てください)。 この方法なら、ページの訪問者は、リンクのクリック回数がカウントされていることにもまったく気がつかないですね。 でも…これ、まだ不完全というか、面倒な点があります。 この方法でリンククリックカウントをするには、全てのリンクタグに onclick〜 というのを加える必要が あります。

onlick を自動で追加する!

ここでまた、今回の研究の見せ場がやってきました…「全てのリンクタグにonclickを自動的に追加するJavaScript」を 作ってしまいましょう!この魔法を使うと、ナント、リンククリックカウントをするには、 ページの最後にスクリプト読み込みタグを1つ追加するだけになります!まさにマジックです。

詳細はこちら… 自動的にonclickを追加するJavaScriptの研究 をご覧下さい。 (スクリプトの影響でリンクのonclickが書き換えられてしまので、このページの中では説明できないのです(^^;

Perl/CGI研究室 'PERL-LABO' TOPへ
戻る(History.Back)

Copyright (c) 'PERL-LABO' All Rights Reserved.  リンクフリーです。