Google

Google AdSense で、広告はページのどの位置に掲載すればいいでしょうか。

<div style="float:left;margin: 5px 15px 5px 0px"> <script type="text/javascript"> </script> <script type="text/javascript" src="https://pagead2.googlesyndication.com/pagead/show_ads.js"> </script>

私は、優秀な技術者たるもの、ウェブ 2.0 のパラダイムの流れの中で、技術の追究だけではなくてウェブ 2.0 流の SEO やマーケティングも知識として知っていなければならないと思うのだ。その急先鋒の1つが AdSense であり、これとどう付き合っていくかも技術者の課題だと思う(たとえば、自分の担当業務に関係なくても、お客様と話しているときに何か提案できることもあるかもしれない)。そしてその AdSense を自身のサイトのデザインの中にどう組み込むかが課題となるが、そのことについてはズバリ、Google の AdSense ヘルプ センター「Google 広告はページのどの位置に掲載すればいいでしょうか。」に詳しい。引用すると、

続きを読む

Google Docs & Spreadsheets で、GoogleLookup と GoogleFinance 関数を試す。

Google のエンジニアの方と話して知ったのだが、Google Docs & Spreadsheets に、ひっそりと GoogleLookup と GoolgeFinance 関数が追加されたようだ(でも調べてみたら 2006/11/30 の Internet Watch に「Google Docs & Spreadsheets」に“Google関数”埋め込み機能など追加 という記事があった)。そこでさっそく試してみた。
まずは GoogleLookup 関数から。

<span style="text-align:center;">

<iframe src="https://spreadsheets.google.com/pub?key=p1ErWQHoVdtMy_c5twTrFTw" marginwidth="0" marginheight="0" width="260" height="122" border="0" frameborder="0" style="border:none;margin-left:125px;" scrolling="no"> </iframe>

作り方は、

  1. Google にアカウントを持ってない人は作る。アカウントっていうのは Gmail でいい。
  2. Google Docs & Spreadsheets に行ってスプレッドシートを新規作成する。
  3. 世界の人口を知るには、セルに =GoogleLookup("world", "population") と入れてみよう。日本の場合は、 =GoogleLookup("Japan", "population")
  4. スプレッドシートを誰からも参照できるように、つまり HP として公開できるように右上のタブから Publish する。これで 5分ごとに更新されるホームページの URL が生成される。
  5. もしスプレッドシートを更新して Re-publish したい場合は、Automatically update every 5 minutes? のところにある Yes ボタンをクリックすると、Re-publish ボタンが有効になる。

    ※Re-publish すると、リンク先の HP の内容も変更されることに注目!(意図的にリロードせず、ずっと表示しているときは 5分後)

  6. ここのエントリーにあるように、ブログなど自分の HP に組み込む場合は <iframe> タグを使うといいだろう。参考までに上記 <iframe> タグの内容は、次のようになっている。 <iframe src="https://spreadsheets.google.com/pub?key=p1ErWQHoVdtMy_c5twTrFTw" marginwidth="0" marginheight="0" width="260" height="122" border="0" frameborder="0" style="border:none;margin-left:125px;" scrolling="no"> </iframe>

次に GoogleFinance 関数を試してみよう。

<span style="align:center;">

<iframe src="https://spreadsheets.google.com/pub?key=p1ErWQHoVdtNASI1MIHO6Sg" marginwidth="0" marginheight="0" width="300" height="165" border="0" frameborder="0" style="border:none;margin-left:125px;" scrolling="no"> </iframe>

作り方は、

  1. Google Docs & Spreadsheets に行ってスプレッドシートを新規作成する。
  2. セルに =GoogleFinance("GOOG", "Price") と入れてみよう。米国の株はティッカーシンボルと呼ばれるアルファベット4文字の組み合わせで社名を表す。これは日本の銘柄コードにあたるのだが、最初の引数にそのティッカーを(この場合は Google のティッカー "GOOG")、2番目の引数に株価なら "Price"、出来高なら "Volume" と入れる。ちなみに Apple のティッカーは AAPL、マイクロソフトは MSFT、アマゾンは AMZN、アドビは ADBE、シスコは CSCO…こんなところか。後は興味のある会社があったら米国ヤフーにでも行って各自で調べてね。
  3. スプレッドシートを誰からも参照できるように、つまり HP として公開できるように右上のタブから Publish する。これで 5分ごとに更新されるホームページの URL が生成される。

    ※米国のマーケットが開いている間は5分後、もしくはマーケットが閉じてしまったら値は更新されないから明日またこのエントリー(HP)に来て数字が変わっているか確かめてみて欲しい。

  4. あとは GoogleLookup のときと同じ。ちなみに株価はマーケットのリアルタイム値から 20分遅れの配信です。

百聞は一見に如かず、このような関数があってはじめてオンラインアプリが活きてくるような気がする。

続きを読む

Movable Type で、Google の SEO 対策をする。

このサイトはほとんどは Google の検索結果をたどって来る方が多い。ここでは、このサイトで実際に施している SEO 対策を紹介しよう。最初に断っておくが、SEO といっても、対象となる検索エンジンは Google オンリーである。

  1. 3日おきに定期的に更新を目標。

    本来なら 「1日ごとに更新」 とした方が格好がいいに決まっているが、どんなに技術に詳しい人でもそんなにたくさん Tips が次から次に書けるわけでもないのは最初から目に見えている。毎日更新するためには Tips を 1年で 365個用意しなければならないことを考えてみて欲しい。それを職業にするなら別の話だが、私の場合は自分の無理のない範囲で最大限の目標値とした。この目標は今のところ守っている。それが守れているのは、その日に公開するエントリーをその日に書いて公開するような自転車操業的なものではなく、ある程度エントリーを書き溜めておいて、Movable Type の 「投稿日」 - 「指定日」 として公開されるようにスケジューリングしているからだと思う。この方法は SEO 対策というよりは、モチベーションを維持する上で自分にとってはうまくいっている。

    Google が一番好むのは良質なサイトから多数のリンクが貼られている(自サイトから貼っているではない)サイトだ。これはブログのエントリーの内容の質を高めることでリンクの数の増やすことができるだろうが、多数の一般サイトからリンクが貼られていればいいというわけでもなく、おそらく Yahoo! から 1つリンクが貼られるだけでそのサイトの価値が高まるだろう。自分の希望通りに価値の高いサイトにリンクが貼ってもらえるとは限らず、こればかりは粛々と良質なエントリーを書いて自サイトの価値を高めるしかない。本当に価値のあるサイトなら向こうからリンクを貼らせて欲しいと依頼やトラックバックが来るだろう。

    では自分にできることは他にはないのだろうか?それは、コツコツ更新することであろう。このサイトはある時点から、エントリーが 100 になるまでは 3日 1回更新することに決めた。今はこのペースを守っている。実際には Google がそれを評価してくれているのかはわからないが、Google の出している特許を読む限りは、放置されているサイトよりは頻繁に更新するサイトの方が評価されるのは確かだろう。

  2. コンテンツを増やす。

    上の 「100 エントリーまでは 3日置きに更新」 と関係するのだが、このサイトは Tips のサイトであるし、もともとウェブサイトはコンテンツが豊富な方が優良なサイトである。Google のサイトにもそう書いてある。従って 100 の Tips 以上にすることを目指した。

  3. サブドメインでアクセスできるようにした。

    当初、このサイトの URL は https://twinkle.cc/perltips/ であったが、https://perltips.twinkle.cc/ に変えた。Google は、ディレクトリが 1 階層深くなるごとにそのページを重要でないとみなしていくからである。また、ドメイン名(この場合はサブドメイン名)が perltips... で始まり、サブドメイン名に perl という重要なキーワードが含まれているため、これも検索キーワードとして重要なポジションになっていると思う。

  4. ディレクト名にキーワードを含めた。

    [続きを読む]

  5. デフォルトのエントリー・ファイル名は使わない。

    個々のエントリーのパーマリンク (Permalink) の名前は必ず自分で考えてつける。
    Google は URL に含まれる文字列(英単語)もキーワードとして考える。Movable Type は、タイトルに含まれる英数字を拾って自動的にエントリー・ファイル名をつけるが、タイトルがすべて日本語だったりすると 「post」 「post_2」 などという、そっけないファイル名をつけてしまう。このサイトは技術的内容を扱うので、例えタイトルが日本語オンリーであっても、できれば検索されやすい英単語を含めたエントリー・ファイル名をつけるようにしている。

    このエントリーの URL は 「https://perltips.twinkle.cc/movable_type/seo.php」 であるはずだ。URL の中に perl ・tips・movable_type・seo というキーワードが含まれていることに注目して欲しい(徹底的に気合を入れるなら、まずはドメイン名を考えるべきだ)。実際 Google で検索してこれらのキーワードがヒットした部分は、Google によって太字にされているはずだ。

  6. Google Sitemap に対応させる。

    [続きを読む]

  7. 無駄なディレクトリ(archives)は省いた。

    Movable Type では、デフォルトの 「アーカイブ」 の場所は archives というディレクトリになっている。しかし Google は長い URL を好まない。archives なるディレクトリを作る目的は、強いていえばサイト運営者がバックアップを取るときに管理しやすいとか、その程度のものであろう。一方、サイトに訪れる人たちは archives というディレクトリがあったとしてもそれは何の意味も成し得ない。このような理由から、archives というディレクトリは省略して、相対パスのルートにアーカイブファイルも置いてしまおう。どうせカテゴリ別にディレクトリが作成されるのだから、archives のディレクトリがある積極的な理由はみつからない。

  8. 個々のエントリーのタイトルは タグにした。

    Google は、見出しダグの 、

    、

    …で囲まれている文字列を、重要なキーワードとして重み付けする。その法則に従って、このブログの見出しもテンプレートの中ですべて にした。Movable Type のデフォルトのテンプレートの見出しは < h3> タグである。見出しの重み付けなど、あくまでもページ内の相対的なものでしかないような気がするので、この方法が有効なのかは実はよくわからない。

  9. タイトルは 「×××で、」 という形で(例えばこのエントリーなら「Movable Type で、Google の SEO 対策をする。」)、重要なキーワードを含めるようにした。

    エントリーのタイトルが h1 タグならば、ここには重要なキーワードが当然入らないと意味がないわけで、そのためにタイトルにはカテゴリを表すキーワードを入れた。たとえばこのエントリーであれば、「Movable Type で、…」 といった書き出しである(特にこのエントリーの内容の場合は Movable Type でなくてもいいのだが、そういうことである)。

  10. できるだけ指示語を使わないでエントリーを書く。

    Google はエントリー中のキーワードを拾う。エントリー中にはそのテーマに関連するキーワードが多ければ多いほど Google はそのエントリーの言いたいことを解釈するという。このことからつまり Google は指示語が苦手なのではという推測が成り立つ。文章をスムーズにするために 「こそあど言葉」 があるのだが、これだとせっかくの キーワードを指示語で置き換えてしまうことになってしまう。従って指示語はなるべく使わず、多少エントリーの文章がしつこくなっても指示語が指す言葉をあえて使うようにしている。

  11. AdSense だけでなくアマゾンのアフィリエイトも貼った。

    Google はそのサイトが表示している広告の質も判断しているらしい。良質なスポンサーと見なすのだろう。そうすると当然 AdSense は貼るべきだが、それは何も考えずに別の実験としてすでにこのサイトには貼ってあった。しかし「広告の質も判断する」 と聞いてアマゾンのアフィリエイトも貼った次第である。ちなみに、このサイトで紹介している Perl の参考書で、実際にクリックして買った方がいたのには驚いた(いやはや、まったく期待していなかったものですから)。アマゾン恐るべし。

  12. ルートディレクトリに robots.txt を置いた。

    Google Sitemap を使っていると、「robots.txt にアクセスできなかった」 といちいちエラーを返す。 仕方がないので以下の内容で robots.txt をルートディレクトリに置いた。

    User-Agent: * Disallow: /images/
  13. サイト内のリンクを増やした。

    Google の SEO で肝となるのは優良サイトからのリンクだ。これは外部からのリンクだが、内部でのリンクもポイントになるという。このサイトでも(というか Movable Type のデフォルトのテンプレートだが)ページの最初のタイトル 「Perl Tips」 をクリックすればどのページからでもトップページに戻れるようになっているが、これは Google にとってはトップページが重要となることを意味する。従って一見マスターベーションのような気もするが、内部のリンクも増やした方がよいだろう。

    内部のリンクとはすなわち、エントリーを書いたら関連しそうな過去のエントリーに対してトラックバックを送るということに他ならない。もちろん、外部のサイトで関連しそうな内容のブログのエントリーがあったらトラックバックを送ると、自動的にそのサイトに自分のサイトへのリンクが貼られるわけだから、これも積極的に行った方がよいだろう。しかしこの方法は時間と手間がかかるので、まずは内部のリンクを増やすことから始めてはどうだろうか、ということだ。

続きを読む

Google Maps APIs で、Firefox や Safari で吹き出しが崩れてしまう。

のように、InfoWindow (吹き出し) を表示する部分のスタイルシートで、以下のように横幅 (width) と white-space: nowrap; を設定する。青い部分を追加。 #InfoWindow {
font-family: "Trebuchet MS", Trebuchet, verdana,"MS Pゴシック", arial, sans-serif;
text-align: left;
<font color="blue">width: 180px;
white-space: nowrap;</font>
}
続きを読む

Movable Type で、Google Sitemap に対応する方法

(Google Sitemap とは?)

Google にキーワードを入力して検索結果が出てくるということは、あらかじめ Google に自分のサイトが登録されているということだ。それは、Google が日夜あなたのサイトを巡回して、ページを Google のシステムの中に貯めているからだ。ではなぜ Google は何億ページもの中から、あれだけ高速に検索結果を出せるのだろう? それには高速に情報を引き出す仕組みが必要となる。それが情報をすばやく検索するための「インデックス化」という仕組みで、検索対象のサイトにインデックスがあると、Google のシステムはは全てのサイトのページにあるキーワードをひとつひとつ探すことなく、高速に検索できるのだ。ちなみにインデックス化の仕組みは MySQL などのデータベースにも備わっているが、Google 自体は自身のインデックス化の仕組みを公開していない (CNET Japan の記事「Flash開発者を不安にさせるGoogle検索の落とし穴」参照)。

Google Sitemap とは、Google に登録する URL を Google に自ら教える仕組みである。これがないと Google はあなたのウェブサイトを勝手に巡回して Google 自身の判断で必要だと思った URL を登録する。ゆえに、Google Sitemap の仕組みを使えば登録して欲しい URL を Google に正確に教えることができるのである。

それではまずは、Google Sitemap に登録しよう → Google Sitemap

(Movable Type で、Google Sitemap に対応する方法)

以下は Niall Kennedy's Weblog に書かれているものの翻訳である。


あなたのブラログの XML サイトマップを Google や他の検索エンジンに解析してもらうのは
とっても簡単。新しいインデックステンプレートを作成して以下のコードをコピーすればよい。
出力ファイルは sitemap.xml のような覚えやすい名前をつけておこう。
そのコードを貼り付けて新しいテンプレートファイルを保存してサイトを再構築すればよい。

以下は、Niall Kennedy's Weblog で提示されている方法に加えて、私の方でカテゴリの URL をサイトマップに加えるように手を加えた sitemap.xml の例である。

<?xml version="1.0" encoding="UTF-8"?> <$MTBlogURL encode_xml="1"$> 1.0 <$MTEntryPermalink encode_xml="1"$> <$MTEntryModifiedDate utc="1" format="%Y-%m-%dT%H:%M:%SZ"$> <$MTCategoryArchiveLink encode_xml="1"$>

最後に、Google Sitemap のサイトにこのファイルを置いた URL (例えば、https://yourdomain.com/sitemap.xml/) を登録すればよい。

続きを読む

Google Maps API で、地図上に経路 / ルート (パス) を表示する

これは、Perl で、Goolge Maps からルートを検索する方法 に対するブラウザ側の処理の例である。以下のコードを参考にして欲しい。repaint メソッドの中でパスを描画している。前提としては以下の通り。

  1. このスクリプトは呼び出し元の HTML から your_ajax_script.js としてリンクされている。
  2. このスクリプトが呼ばれる HTML には、
    があるとする。
  3. init メソッドは、HTML の onLoad から呼ばれるものとする。

your_ajax_script.js の例

//<![CDATA[ var BASE_URL = 'https://yourdomain.com'; var CGI_FILE = '/path_to_cgi_dir/your.cgi'; var DEFAULT_ZOOM = 5; var map; var currentPoint; // init は、HTML の onLoad から呼ばれるものとする。 function init() { <pre>currentPoint = new GPoint(-122.13930130004883, 37.40248284497232); map = new GMap(document.getElementById('map')); GEvent.addListener(map, 'moveend', function() { // add your code here }); GEvent.addListener(map, 'click', function(o, p) { // add your code here }); GEvent.addListener(map, 'infowindowopen', function() { // add your code here }); GEvent.addListener(map, 'infowindowclose', function() { // add your code here }); map.setMapType(G_MAP_TYPE); map.centerAndZoom(currentPoint, DEFAULT_ZOOM); map.addControl(new GLargeMapControl()); map.addControl(new GMapTypeControl()); map.addControl(new GScaleControl()); } function repaint(xml) {
var list_html = '';

if(xml) {

    // IE の場合はより厳密にチェックが必要、Firefox は xml だけでよい
    if(xml.documentElement) {

        var path = xml.documentElement.getElementsByTagName('path');

        var points = [];
        for (var i = 0; i < path.length; i++) {
            points.push(new GPoint( path[i].getAttribute('lng'),
                                    path[i].getAttribute('lat')));
        } // End of for

        var route = xml.documentElement.getElementsByTagName('route');
        list_html += route.length > 0 ? '<ol>' : '';
        for (var i = 0; i < route.length; i++) {
            list_html += '<li>' + route[i].getAttribute('description') + '</li>';
        } // End of for
        list_html += route.length > 0 ? '</ol>' : '';
    }
}

// このスクリプトが呼ばれる HTML には、<div id="list"></div> があるとする。
document.getElementById('list').innerHTML =  list_html;
map.addOverlay(new GPolyline(points));
} // getPath メソッドは、マウスでボタンが押された、などのイベントに反応する function getPath(lng, lat) {
currentPoint = new GPoint(lng, lat);

post(    'do=path'
    +    '&toX=' + lng
    +    '&toY=' + lat);
} // post メソッドは、例えば getPath メソッドから呼ばれる function post(data) {
var xmlHttp = GXmlHttp.create();

xmlHttp.onreadystatechange = function() {

    if (xmlHttp.readyState == 4) {
        var xml = xmlHttp.responseXML;
        repaint(xml);
    }
}

xmlHttp.open('POST', BASE_URL + CGI_FILE, true);
xmlHttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
xmlHttp.send(data);
} //]]>
続きを読む

Perl で、Excel のデータ (XML) をアップロードして処理する方法

  1. まず、Excel で 以下のように category1、category2、name、address、phone、link、comment1、comment2 というカラム構成のワークシートを作成し、適当にデータを入力、XML 形式で保存しておく。
    注: 住所は米国の住所でないと正しく処理されないことに注意
  2. 次に、以下にあるように gmap_excel.html と gmap_excel.cgi の 2つのファイルを用意する (.gmap_excel.cgi 中のパスの設定などは適宜変更のこと)。
  3. gmap_excel.html から上の XML ファイルをサーバにアップロードする。
  4. サーバ側では Excel の XML データを処理して、gmap_excel.xml というファイルが出力される。
  5. このサーバ側で出力された gmap_excel.xml ファイルは Google Maps API を使った AJAX クライアントから利用できる。

gmap_excel.html のファイルの内容

<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <link rel="stylesheet" href="styles-site.css" type="text/css" />
</head>
<body>
    <form enctype="multipart/form-data" action="gmap_excel.cgi" method="post">
        <input type="hidden" name="MAX_FILE_SIZE" value="2000000" />
        <table width="600">
            <tr><td>Names file:</td><td><input type="file" name="file" />
                    <input type="submit" value="Upload" /></td></tr>
        </table>
    </form>
</body>

gmap_excel.cgi のファイルの内容

#!/usr/bin/perl use lib "path_to_your_perl_lib/lib/perl5/site_perl"; use strict; use Geo::Google; use CGI; our $XML_HEADER = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"; # XML ヘッダ our $HOME_DIR = 'your_home_dir'; our $LOCK_DIR = 'path_to_lock_dir/lock'; # do chmod 777 path_to_lock_dir/lock our $LOCK_FILE = 'lock'; our $XML_FILE = 'path_to_your_output_xml/gmap_excel.xml'; # 出力用 XML ファイル名 our $col_index = 0; # Excel シートの現在の列(カラム)インデックス our $row_index = 0; # Excel シートの現在の行インデックス our @data = (); # 出力用データ our @current_data = (); # 現在のデータ # オブジェクト初期化 our $CGI = new CGI; our $GEO = new Geo::Google; # HTML 出力 print qq|Content-type: text/html\n\n|; print qq||; print qq||; print qq|

|; init(); print qq|

|; # 個々のデータのハンドラ sub dataHandler {
my ($expat, $text) = @_;

#  $row_index = 0 と 1 は、Excel で データのヘッダのため必要なし
if($text !~ /^\s+$/ && $row_index > 1) {    #  空白行でなければ
    $current_data[$col_index] = $text;
}
} # 要素の開始 sub startElement {
my ($expat, $tag, %attr) = @_;

if($tag eq 'Row') {            #  <Row>で始まるとき

    $col_index = 0;                #  カラムを初期化
    $row_index++;                #  行を進める
    @current_data = ();            #  現在の行データを初期化
}

if($tag eq 'Data') {            #  <Data>で始まるとき

    $col_index++;                #  列を進める
}
} # 要素の終了 sub endElement {
my ($expat, $tag) = @_;
my ($xml, $html);
my ($lng, $lat, $name, $link, $category1, $category2);
my ($street, $city, $state, $phone, $comment1, $comment2);

#  </Row> のとき
if($tag eq 'Row') {

    push(@data, {    # データに現在の行データを代入

        'category1' => $current_data[1],
        'category2' => $current_data[2],
        'name'      => $current_data[3],
        'address'   => $current_data[4],
        'phone'     => $current_data[5],
        'link'      => $current_data[6],
        'comment1'  => $current_data[7],
        'comment2'  => $current_data[8]
    });
}

#  </Workbook> のとき
if($tag eq 'Workbook') {

    $row_index = -1; #  行数を初期化 ($row_index = 0 はヘッダのため -1 からスタート)
    foreach my $row (@data) {

        $row_index++;

        if($row->{address}) {
            $lng = '';  $lat = '';
            my ($degree) = getDegrees($row->{address});
            if($degree) {
                $lng    = $degree->longitude;
                $lat    = $degree->latitude;
            }
        }

        $name      = $row->{name};
        $link      = $row->{link}
                   =~ /http:\/\/[!#-9A-~]+\.+[a-z0-9]/ ? $row->{link} : '';
        $category1 = $row->{category1};
        $category2 = $row->{category2};
        ($street, $city, $state) = split(',', $row->{address});
        $street    = $street;
        $city      = $city;
        $state     = $state;
        $phone     = $row->{phone};
        $comment1  = $row->{comment1} eq '-' ? '' : $row->{comment1};
        $comment2  = $row->{comment2};

        #  lng と lat が検索できたら (データが入っているということだから)
        if($lng && $lat) {

            $xml    .= "\t<marker\n"
                    .  "\t\tlng       = \"$lng\" lat = \"$lat\"\n"
                    .  "\t\tname      = \"" . $name      . "\"\n"
                    .  "\t\tlink      = \"" . $link      . "\"\n"
                    .  "\t\tcategory1 = \"" . $category1 . "\"\n"
                    .  "\t\tcategory2 = \"" . $category2 . "\"\n"
                    .  "\t\taddress1  = \"$street\"\n"
                    .  "\t\taddress2  = \"$city, $state\"\n"
                    .  "\t\tphone     = \"$phone\"\n"
                    .  "\t\tcomment1  = \"$comment1\"\n"
                    .  "\t\tcomment2  = \"$comment2\"\n"
                    .  "\t/>\n\n";

        } elsif($row_index) {

            $html   .= '<tr><td>'
                    .  "$row_index / $name / $street, $city, $state"
                    .  '</td></tr>';
        }
    }

    $xml    =  $XML_HEADER
            .  "<markers>\n"
            .  $xml
            .  "</markers>\n";

    if($html) {    #  エラーがあれば
        $html    = '<table>'
                 . '<tr><td>***** 以下、緯度経度が検索不能でした。</td></tr>'
                 . $html
                 . '</table>';
    } else {    #  エラーがなければ
        print '<br />done.';
    }

    #  ファイルのオープン
    &file_lock;        #  ファイルロック
    open(XML, ">$HOME_DIR$XML_FILE")
    or die('Cannot open an XML file: ' . "$HOME_DIR$XML_FILE");
    print XML $xml;    #  書き込み
    close(XML);        #  ファイルを閉じる
    &file_unlock;      #  ロック解除

    print $html;
}
} sub getDegrees { # 住所から緯度経度を検索
return $GEO->location( address => shift); # shift = address / リファレンスを返す
} sub init() {
# XMLパーサー作成 ('UTF-8')
my $xml_parser = new XML::Parser(   ProtocolEncoding => 'UTF-8',
                                    Handlers=>{ Start=>\&startElement,
                                                End  =>\&endElement,
                                                Char =>\&dataHandler });
# ファイルのオープンはいらない。input タグで指定した name 属性がそのままファイルハンドルになる
my $xml = $CGI->param('file');

# XMLパース処理
$xml_parser->parse($xml) or    die "XML error: $xml_parser";

# ファイルクローズ
close($xml);
} sub file_lock {
my $wait = 5;
while (!symlink('.',"$HOME_DIR$LOCK_DIR/.$LOCK_FILE")) {
    if (--$wait <= 0) {
# &error( '現在他の方が使用中です。', # 'しばらくしてから再度ご利用ください。');
    }
    sleep (1);
}
} sub file_unlock {
unlink ("$HOME_DIR$LOCK_DIR/.$LOCK_FILE");
} 1;

gmap_excel.xml 出力例

<?xml version="1.0" encoding="UTF-8"?>
<marker
    lng       = "-122.125690" lat = "37.413570"
    name      = "Tofu House"
    link      = ""
    category1 = "Restaurant"
    category2 = "Korean"
    address1  = "4127 El Camino Real"
    address2  = " Palo Alto,  CA 94306"
    phone     = "650-424-8805"
    comment1  = ""
    comment2  = "Santa Clara の Tofu House と同じ店。"
/>
...
続きを読む

Perl で、住所から緯度経度を取得する方法

Geo::Google モジュールを利用する (米国)。住所を渡せばコーディング的にはほとんど 1行で緯度経度を返してくれる。Google Maps にアクセスしにいって緯度経度を取ってきていてるので、地図データベースは Google Maps のものである。以前紹介した PHP のときのように SOAP も何もいらない (Geo::Google は、内部で LWP::Simple を利用している)。PHP の Geocoder 版は、Geocoder のデータベースに SOAP 経由でアクセスする。少し使ってみた結果、Geocoder のデータベースは少しズレが生じるようである (米国の場合)


use utf8;
use Encode;
use Geo::Google;
use XML::Parser;
#!/usr/bin/perl use utf8; use Encode; use Geo::Google; use XML::Parser; my $lng, $lat; my $address1 = 'your address part 1 here'; my $address2 = 'your address part 2 here'; my ($degree) = getDegrees("$address1 $address2"); if($degree) {
$lng = $degree->longitude;
$lat = $degree->latitude;
} else {
$lng = ''; $lat = '';
} sub getDegrees { # 住所から緯度経度を検索
return $GEO->location( address => Encode::encode_utf8(shift));
                                                    # shift = address / リファレンスを返す
}
続きを読む

ブログ (Movable Type) と Google Map を組み合わせる

今回取り組む内容の仕様としては、以下の通りである。

  • ブログを利用する。
  • ブログに自分の好きな地域(どこかは予め決めておく)の地図を表示する。
  • 地図にはマーカーが表示される。
  • マーカーの情報は AJAX (XMLHttpRequest) の非同期通信により、サーバーから XML ファイルを読み込んだものである。
  • マーカーをクリックすると吹き出しにその地点の情報が出る。
  • 吹き出し中の「続きを読む」リンクをクリックすると、ブログエントリにジャンプする。
  • マーカーは自分独自のアイコンを使う。

まずは、実例をみてイメージをつかんでもらった方がいいだろう。

このサイトで動作している JavaScript は以下のものである。

//<![CDATA[ var BASE_URL = "https://2kids.net"; var GMAP_FILE = "/yas/gmap.xml"; var ICON_DEFAULT = "/yas/images/icon_restaurant.png"; var ICON_SHADOW = "/yas/images/icon_restaurant_shadow.png"; var map; var baseicon; var xmlHttp; function init() { <pre>map = new GMap(document.getElementById("map")); // 地図オブジェクトを生成 baseicon = new GIcon(); // アイコンオブジェクトを作成 xmlHttp = GXmlHttp.create(); // XmlHttpRequest オブジェクトを作成 // 地図を設定 map.addControl(new GLargeMapControl()); // 拡大縮小のボタン map.addControl(new GMapTypeControl()); // 地図と衛星の切り替え map.centerAndZoom(new GPoint(-122.0745, 37.4170), 7); // ベイエリアを表示 // アイコンを設定 baseicon.image = BASE_URL + ICON_DEFAULT; baseicon.shadow = BASE_URL + ICON_SHADOW; baseicon.iconSize = new GSize (16, 16); baseicon.shadowSize = new GSize (34, 20); baseicon.iconAnchor = new GPoint( 8, 8); // <- (icon_width / 2, icon_height) baseicon.infoWindowAnchor = new GPoint( 9, 2); baseicon.infoShadowAnchor = new GPoint(18, 25); // マーカーを設定: XML データを読み込んで表示 xmlHttp.open("GET", BASE_URL + GMAP_FILE, true); xmlHttp.onreadystatechange = showMarkers; xmlHttp.send(null); } function showMarkers() {
if (xmlHttp.readyState == 4) {

    var xmlDoc = xmlHttp.responseXML;
    var marker = xmlDoc.documentElement.getElementsByTagName("marker");
    for (var i = 0; i < marker.length; i++) {
        addMarker(marker[i]);
    } // End of for
}
} function addMarker(xml) {
var point  = new GPoint(xml.getAttribute("lng"),
                        xml.getAttribute("lat"));
baseicon.image = BASE_URL + xml.getAttribute("icon");
var icon   = new GIcon(baseicon);
var marker = new GMarker(point, icon);
map.addOverlay(marker);
var html   = '<div id="InfoWindow">'
           + '<img src="' + baseicon.image + '" alt="icon"> '
           + '<a href="' + xml.getAttribute("site") + '">'
           + xml.getAttribute("name")
           + '</a><br />'
           + xml.getAttribute("street") + '<br />'
           + xml.getAttribute("city")   + '<br />'
           + xml.getAttribute("phone")  + '<br />'
           + '<a href="' + BASE_URL + xml.getAttribute("link") + '">'
           + 'レビューを読む'
           + '</a><br />'
           + '</div>';
GEvent.addListener(marker, "click", function() {
//  marker.showMapBlowup(3);  // 吹き出しに地図が表示される模様。
//  map.centerAndZoom(p, 3);
    marker.openInfoWindowHtml(html);
});  // click のイベントリスナ登録
} //]]>

このスクリプトは以下のようなフォーマットの XML データを利用する。

<marker
    lng="-121.9485855102539" lat="37.318707484418496"
    icon="/yas/images/icon_mexican.png"
    name="Chevys Winchester"
    site="https://www.chevys.com/"
    link="/yas/archives/cat60/#a000761"
    street="550 S. Winchester"
    city=" San Jose, CA 95128"
    phone="(408) 241-0158"
/>

さて、それでは仕組みについてひとつひとつ説明していこう。 今回の動作確認済み環境としては、以下の通りである (2005/10/28 現在)。

<ul><li>Movable Type 3.2 Release 2 (日本語版)</li><li>Firefox 1.0.7 または IE 6.0SP2 または Safari 2.0.1</li></ul>

というわけでここでは Movable Type 3.2 Release 2 (日本語版) と Firefox 1.0.7 を例に取って話を進める。以下は必要な手順である。

  1. アイコンの作成 (Google Map に表示するマーカーのこと)
  2. JavaScript 作成 (Google Map 用)
  3. map.xml の作成 (XMLHttpRequest を使ってマーカーの情報を読み込む)
  4. ブログテンプレートの修正
  5. スタイルシートの設定
  6. ブログエントリの追加

それではまずはアイコンについ説明しよう。

  • Google Map API では、マーカーと呼ばれるポイントを指し示すアイコンが必要となる。Google が用意したデフォルトのマーカーアイコンはオレンジ色の水玉を逆さにしたような感じのものだが、これは自由にカスタマイズできる。
  • アイコンの実体は画像ファイルである。画像のフォーマットは、JPEG、GIF、PNG が使えるが、PNG がいいだろう。
  • なぜなら、アイコンには影を付けられるのだが、この影は、αチャネルを透過にした PNG を使うことになっているからだ (まぁ、どの画像フォーマットを選ぶかは実際は好みの問題だ)。
  • ちなみにアイコンの影は、オリジナルのアイコンに対して45度の傾きを付けるのが、Google からのガイドラインのようである。実際影をつけるのは結構難しかった。私の場合はオリジナル画像をグレー処理し、その後何度かソフト処理をし、ぼかしをかけた…という感じで、この作業に多くの時間を取ってしまった^^;

以下、JavaScript からのアイコン部分生成に関する抜粋だ。要は、GIcon オブジェクトに用意されているいろいろなプロパティを設定してあげれば、自分で作ったアイコンが表示されるのである。

var BASE_URL = "https://2kids.net"; var baseicon; function init() {
baseicon = new GIcon();  // アイコンオブジェクトを作成

// アイコンを設定
baseicon.image            = BASE_URL + "/yas/images/icon_restaurant.png";
baseicon.shadow           = BASE_URL + "/yas/images/icon_restaurant_shadow.png";
baseicon.iconSize         = new GSize (16, 16);
baseicon.shadowSize       = new GSize (34, 20);
baseicon.iconAnchor       = new GPoint( 8,  8);  // <- (icon_width / 2, icon_height)
baseicon.infoWindowAnchor = new GPoint( 9,  2);
baseicon.infoShadowAnchor = new GPoint(18, 25);
baseicon.image = BASE_URL + xml.getAttribute("icon");
} function addMarker(xml) {
var point  = new GPoint(xml.getAttribute("lng"),
                        xml.getAttribute("lat"));
baseicon.image = BASE_URL + xml.getAttribute("icon");
var icon   = new GIcon(baseicon);
var marker = new GMarker(point, icon);
map.addOverlay(marker);
} //]]>

次に肝心の JavaScript であるが、Movable Type のテンプレート作成機能を利用する。Movable Type で、環境設定 / テンプレート-モジュールと選択していき、「モジュールを新規作成」をクリックして以下のように作成(設定)し、保存する。

  • テンプレート名: gmap.js (←ここは実は何でもいい)
  • このテンプレートにリンクするファイル: gmap.js (別のテンプレートから使用するファイル名)
  • モジュールの内容: 冒頭の JavaScript

JavaScript を保存したら、


map.xml

というファイル名で、XML ファイルを保存する。以下に XML ファイルの内容 (属性) を説明しよう (属性は独自に設定したものです)。

<marker
    lng="-121.9485855102539" lat="37.318707484418496" <font color="blue">← ここは、</font><b><font color="orange">経度</font><font color="blue">・</font><font color="red">緯度</font></b><font color="blue">の順で入る</font>
    icon="/yas/images/icon_mexican.png" <font color="blue">← アイコン画像へのルートからのパス + ファイル名 (https:// は、JavaScript 中の最初に記述済み)</font>
    name="Chevys Winchester" <font color="blue">← 吹き出し中の一番上に表示される、マーカーの名前</font>
    site="https://www.chevys.com/" <font color="blue">← マーカーの名前をクリックすると表示されるウェブページ</font>
    link="/yas/archives/cat60/#a000761" <font color="blue">← Movable Type のブログのエントリへのリンク※</font>
    street="550 S. Winchester" <font color="blue">← マーカーの住所 (サンプルはアメリカなので番地が先)</font>
    city=" San Jose, CA 95128" <font color="blue">← マーカーの住所 (サンプルはアメリカなので市町村がが後)</font>
    phone="(408) 241-0158" <font color="blue">← 電話番号</font>
/>

※…「Movable Type のブログのエントリへのリンク」とあるのは、個別ブログについている ID である。個々のブログエントリのソースを見ればわかると思う。
これでスクリプト & XML データの準備が整うので、テンプレートを修正する。環境設定 / テンプレートで、

  • メインページ
  • アーカイブ → カテゴリーアーカイブ
  • アーカイブ → 日付アーカイブ
  • アーカイブ → 個別エントリーアーカイブ

のすべてのテンプレートにおいて、

… <script src="https://maps.google.com/maps?file=api&v=1&key=ここにあなたが取得した Google Map API のキーが入る" type="text/javascript"</script> <script src="/ルートからブログへのパス/gmap.js" type="text/javascript"></script> <body onLoad="init()"> …

のように修正する。onLoad="..." で最初に呼ばれる関数を指定しないと、IE ではうまく動作しなかった。
また、吹き出し中に表示されるリンクをクリックすることによって、個別のブログエントリにジャンプできるように、テンプレートを少し修正する。ブログエントリのタイトルを表示する箇所を見つけ、以下のように... タグをはさむ。

">

"><$MTEntryTitle$>

また、個別エントリから地図に戻れるように、以下の部分の最後に「地図に戻る」リンクを追加する。「#a000835」とある部分は、個別ブログエントリで、Google Map を表示したいブログエントリの ID である。

投稿者 <$MTEntryAuthor$> : "><$MTEntryDate format="%Y/%m/%d"$> | #comments">コメント (<$MTEntryCommentCount$>) | #trackbacks">トラックバック | 地図に戻る

続いてスタイルシートも設定してしまおう。Movable Type のテンプレート→スタイルシートで、スタイルシートの最後に以下の内容を追加する。

#map {
font-family: "Trebuchet MS", Trebuchet, verdana, arial, sans-serif;
text-align: center;
} #InfoWindow {
font-family: "Trebuchet MS", Trebuchet, verdana, arial, sans-serif;
}

こんな具合である。#map と #infoWindow を自由にいじってみて欲しい (#InfoWindow は実は JavaScript 中にそのように設定できるように記述してある)。
最後はブログエントリの追加である。ブログの本文に、以下の1行を追加すれば Google Map が表示される。width と height は地図の大きさなので自由に設定して欲しい。

<div id="map" style="width: 500px; height: 400px;">
続きを読む
Google を購読