Analog Studio

郵便番号から自動で住所を検索する方法【Javascript】

概要

Web サイトに訪れてくれた方からのお問い合わせにフォームを使うことは多いと思います。
メールクライアントソフトを起動させることなく、ブラウザ上から手軽に送信できる利点は大きいです。
また、必要な項目が予め表示されているので記載すべき内容をユーザが考えなくても良いというところも大事ですね。

さてそんな便利なフォームですが、住所の入力をお願いしたいという管理者の方も多いのではないでしょうか?
しかし住所の入力は億劫な方が多いのも事実です。少なくとも私は好きではありません(笑)
せっかくお問い合わせしようとしても面倒な項目が必須だと送信を躊躇ってしまうこともあります。

そこで、Javascript を用いて郵便番号から自動的に住所を検索してユーザの利便性を上げる方法を紹介します。
コンセプトは「ユーザの手間を少しでも減らす」です。
また、どこにでも軽量に組み込めるように jQuery は使いません。

まずは、完成形のコードから!

そんなに難しいことは無いので、まずは完成形のコードを以下に紹介します。
コード上にコメントを入れてあるので少し詳しい方ならすぐに理解されると思います。

ZipCloudにHTTPでリクエストする為のPHP → いつも間にかHTTPSに対応していました!

今回紹介する方法は株式会社アイビスさんが提供して下さっている ZipCloud という API サービスを利用しています。
こちらの API は SSL に対応していません。
(2022-03-03 追記) いつの間にか API が SSL に対応しましたのでこの中継用の PHP などは不要になりました!Javascript で直接リクエストをすれば OK です! ですので SSL を使用すべきお問い合わせページなどから直接呼び出すとブラウザがリクエストをブロックしてしまうことがあります。
そこで、ZipCloud にはあなたのサイトを運営しているサーバから非 SSL でリクエストを送受信するようにします。

ユーザから直接、非 SSL 通信を行うわけではないので仮に郵便番号を盗聴されてもサーバからのリクエストが見えるだけなのでユーザと郵便番号を結び付けられることはないです。
(サーバがクラッキングされた、という非常事態は除きますが)

<./zipcode.php> <?php // 呼び出したURLの'?'以降の'zipcode='で指定された文字列を取得する (GET) $zipcode = ''; if (!empty($_GET['zipcode'])) { $zipcode = $_GET['zipcode']; } // 呼び出したURLの'?'以降の'callback='で指定された文字列を取得する (GET) // 指定がなければ'jsonp'というコールバック関数名で返す $callback = 'jsonp'; if (!empty($_GET['callback'])) { $callback = $_GET['callback']; } // ZipCloudのAPI用のアドレス文字列を生成 $url = "http://zipcloud.ibsnet.co.jp/api/search?zipcode={$zipcode}&callback={$callback}"; // テキストデータを読み込む (HTTP通信) $json = file_get_contents($url); // 文字化けしないようにUTF-8に変換 $json = mb_convert_encoding($json, 'UTF8', 'ASCII,JIS,UTF-8,EUC-JP,SJIS-WIN'); // 取得した文字列をそのまま返す print_r($json); ?>

見ての通り、ユーザから受け取った郵便番号を ZipCloud に問い合わせて戻ってきた文字列を返すだけという簡単なプログラムです。
ここでは PHP を使っていますが、Perl でも Ruby でもサーバ側で動作するものならどんな方法でも良いです。

HTMLとJavascript

フォームを想定しているので <INPUT> 要素に郵便番号が入力されたら自動的に確認しに行って、住所が取得できれば住所を自動入力します。

<HTML> <table><tr> <th><label for="address_num">郵便番号</label></th> <td>〒<input size="20" type="text" name="郵便番号" maxlength="9" type="tel" id="address_num"></td> </tr><tr> <th><label for="address_name">ご住所</label></th> <td><input size="30" type="text" name="ご住所" id="address_name"></td> </tr></table> <Javascript> <script type="text/javascript"><!-- var pastAddress; window.addEventListener("load", function(){ document.getElementById("address_num").addEventListener("change", function(){ var _address = this.value.replace(/[0-9]/g, function($s){ return String.fromCharCode($s.charCodeAt(0) - 65248); }).replace(/\D/g, ""); if(_address.match(/^\d{7}$/)){ if(pastAddress != _address){ var _zipcloudAPI = document.body.appendChild(document.createElement("script")); _zipcloudAPI.src = "./zipcode.php?zipcode=" + _address + "&callback=getAddNameByZipcloudAPI"; _zipcloudAPI.onload = function(){ document.body.removeChild(_zipcloudAPI); }; pastAddress = _address; } document.getElementById("address_num").value = _address.slice(0, 3) + "-" + _address.slice(-4); } }, false); }, false); var getAddNameByZipcloudAPI = function( $getAdd ){ var _addFormatted = ""; if($getAdd.status == 200){ _addFormatted += $getAdd.results[0].address1; // 都道府県名 _addFormatted += $getAdd.results[0].address2; // 市町村名 _addFormatted += $getAdd.results[0].address3; // 町域名 } document.getElementById("address_name").value = _addFormatted; }; //--></script>

ZipCloud にリクエストするタイミングは、フォームの内容が変更された時です。
全角は半角に自動変換しています。数字以外の文字は全て無視します。
上記コードを実行すると以下のようになります。

変更されたタイミングで自動的に検索して取得できれば表示するようにしてあるので、ユーザの手間は最小限です。
"住所検索" などというボタンを設置しているフォームも多いですが、そのひと手間が利便性を下げるのでボタンは無い方が良いと思います。
(Javascript が使えない場合や API が落ちている場合にもそのボタンを押しても動きが無いのでユーザにストレスを与えますしね)

コードの仕組みと解説

では、コードの解説をしていきます。
難しい所は無いので簡単にまとめます。

Javascriptで郵便番号を整形し、APIを読み込む

ページが読み込まれたらイベントを設定して、郵便番号を整形していきます。
ZipCloud は利便性の高い API ですが、郵便番号には半角数字を渡す必要があります。
(半角数字以外は取り除いて認識されるようです)

// 一つ前の郵便番号を格納しておく var pastAddress; // ページ読込が完了したらイベントを登録する window.addEventListener("load", function(){ document.getElementById("address_num").addEventListener("change", function(){ // 全角数字を半角に変換する // 変換後に半角数字以外を削除する var _address = this.value.replace(/[0-9]/g, function($s){ return String.fromCharCode($s.charCodeAt(0) - 65248); }).replace(/\D/g, ""); // 7桁の数字になっていれば、住所検索を開始する if(_address.match(/^\d{7}$/)){ // 一つ前に検索した住所と同じ場合は住所検索しない if(pastAddress != _address){ var _zipcloudAPI = document.body.appendChild(document.createElement("script")); _zipcloudAPI.src = "./zipcode.php?zipcode=" + _address + "&callback=getAddNameByZipcloudAPI"; _zipcloudAPI.onload = function(){ document.body.removeChild(_zipcloudAPI); }; pastAddress = _address; } // 「3桁-4桁」の形式で整形した郵便番号に置き替える document.getElementById("address_num").value = _address.slice(0, 3) + "-" + _address.slice(-4); } }, false); }, false);

まずは、addEventListener 関数でイベントを登録します。
DOM ツリーが構成されてからでないと <INPUT> 要素の取得に失敗するので、ページの読込完了後か DOM ツリー構成後に登録します。
(DOM ツリー構成後にする場合は、一つ目の addEventListener の第1引数は "DOMContentLoaded" です)
document.getElementById("address_num") で <INPUT> 要素を選択して内容変更を検出する "change" イベントを登録します。

内容変更を検出したら入力内容を整形します。
まずは replace メソッドで全角数字を半角数字に置換します。

var _address = this.value.replace(/[0-9]/g, function($s){ return String.fromCharCode($s.charCodeAt(0) - 65248); });

この部分のミソは replace メソッドの第2引数に関数を与えていることです。
ここに関数を入れると、その関数の引数に replace メソッドの第1引数にしていした正規表現にマッチした文字列が代入されます。
正規表現では全角数字がマッチするので全角数字を半角数字に変換して返せば置換されます。
全角数字と半角数字は文字コードで65248違うのでこのようなコードで変換ができます。
分かりにくければ全角数字をキーにした連想配列を用意しても良いです。

全角・半角の変換ができたら、続けて半角数字以外を全て削除します。
これも replace メソッドと正規表現で対応しています。( "\D" は "半角数字以外" を表現できます。[^0-9] でも同じです)

// 7桁の数字になっていれば、住所検索を開始する if(_address.match(/^\d{7}$/)){ // 一つ前に検索した住所と同じ場合は住所検索しない if(pastAddress != _address){ // ZipCloudに問い合わせる // ここで問い合わせる処理をする // pastAddress = _address; } }

続いて整形された郵便番号を確認します。
郵便番号なので7桁が必要です。また、整形後に直前に入力した郵便番号と同じでないことを確認します。
ここまでくれば ZipCloud へのリクエストが投げられます。

var _zipcloudAPI = document.body.appendChild(document.createElement("script")); _zipcloudAPI.src = "./zipcode.php?zipcode=" + _address + "&callback=getAddNameByZipcloudAPI"; _zipcloudAPI.onload = function(){ document.body.removeChild(_zipcloudAPI); };

ZipCloud API は、コールバック関数の引数に JSON 形式のデータを入れて結果を返してもらうことができます。
これを利用するとコールバック関数を予め定義しておけば、API の結果を <SCRIPT> 要素で読み込むことでコールバック関数の引数として結果を動的に取得し、利用することができます。うまくできていますね。

このために、appendChild メソッドと createElement メソッドを組みわせて API の結果を読み込む準備をします。
document.body.appendChild(document.createElement("script")) で新しく <SCRIPT> 要素を作成して <BODY> 要素の末尾に追加します。
appendChild の返り値はこの新しく作った要素へのセレクタになるので、変数に入れておきます。

読み込む API のアドレスを指定すれば自動的にリクエストが送信されます。
API から結果が返ってくれば直ぐにコールバック関数が実行されます。
読込後は不要になった要素を removeChild メソッドで削除してメモリを開放しておきます。

ZipCloud API にコールバック関数を返してもらう場合は、リクエスト URL の "?" 以降に "callback=任意の関数名" で定義した関数名を指定します。
※ここでは SSL 通信と非 SSL 通信の橋渡しをするだけの PHP を呼び出しますが、直接呼び出す場合も同じです。

APIから結果を受け取るコールバック関数

API の結果を Javascript で受け取りにはコールバック関数の引数で受け取るのが最も簡単です。

例えば、http://zipcloud.ibsnet.co.jp/api/search?zipcode=7830060&callback=sukina_namae にアクセスすると以下の文字列が返ってきます。
見ての通り、JSON 形式のデータをを引数に入れた関数の呼び出し、となります。

sukina_namae ( { "message": null, "results": [ { "address1": "高知県", "address2": "南国市", "address3": "蛍が丘", "kana1": "コウチケン", "kana2": "ナンコクシ", "kana3": "ホタルガオカ", "prefcode": "39", "zipcode": "7830060" } ], "status": 200 })

このような Javascript コードが読み込まれるのでコールバック関数を予め用意して引数として値を受け取ります。

var getAddNameByZipcloudAPI = function( $getAdd ){ var _addFormatted = ""; if($getAdd.status == 200){ _addFormatted += $getAdd.results[0].address1; // 都道府県名 _addFormatted += $getAdd.results[0].address2; // 市町村名 _addFormatted += $getAdd.results[0].address3; // 町域名 } document.getElementById("address_name").value = _addFormatted; };

JSON 形式のデータは上記のコードだと変数 $getAdd に入るので必要な文字列になるように連結して、住所欄に結果を入れてやれば完成です。

SSLと非SSLを変換するPHP

ZipCloud は SSL 通信に対応していないので、SSL 化されたページからの読み込みはブラウザが自動的にブロックしてしまうことがあります。
最近では、非 SSL サイトが危険なページであるとブラウザのアドレスバーに表示されることも多いです。

非SSLページは不安を煽る表示が出ます。こんな表示があるページから問い合わせなんてできませんよね。

そこで、SSL 保護された通信を使うために一旦 SSL 化されたサイト内の PHP を経由させることでブロックされることを防ぎます。
郵便番号に重要な個人情報はありませんが、上記のような怖い表示がでないようにユーザが直接アクセスするところは全て SSL 通信できるようにしましょう。

// 呼び出したURLの'?'以降の'zipcode='で指定された文字列を取得する (GET) $zipcode = ''; if (!empty($_GET['zipcode'])) { $zipcode = $_GET['zipcode']; } // 呼び出したURLの'?'以降の'callback='で指定された文字列を取得する (GET) // 指定がなければ'jsonp'というコールバック関数名で返す $callback = 'jsonp'; if (!empty($_GET['callback'])) { $callback = $_GET['callback']; } // ZipCloudのAPI用のアドレス文字列を生成 $url = "http://zipcloud.ibsnet.co.jp/api/search?zipcode={$zipcode}&callback={$callback}"; // テキストデータを読み込む (HTTP通信) $json = file_get_contents($url); // 文字化けしないようにUTF-8に変換 $json = mb_convert_encoding($json, 'UTF8', 'ASCII,JIS,UTF-8,EUC-JP,SJIS-WIN'); // 取得した文字列をそのまま返す print_r($json);

まずはリクエスト URL から郵便番号とコールバック関数名を取得します。
PHP では $_GET という特殊変数に "?" 以降の情報が格納されているので例外処理などをしていい感じにしておきます。
もちろん filter_input(INPUT_GET, 'キー') で取得しても良いと思います。

準備ができたら、非 SSL 通信 (http://~) で ZipCloud API にアクセスします。
PHP からは file_get_contents 関数を使って結果を受け取ります。

受け取った結果を文字化けしないように UTF-8 に変換して結果を表示させます。
UTF-8 以外の文字コードを使っている方は合わせて変更して下さい。
ちなみにですが、mb_convert_encoding 関数の第3引数に "auto" は設定しない方が無難です。

まとめ

以上、Javascript で郵便番号から住所を自動取得する方法でした。

ユーザの利便性を上げることはお問い合わせのハードルを下げることになるので是非導入したいところですね。

また、株式会社アイビスさんには素晴らしいサービスをご提供頂き感謝致します。
この場を借りて御礼申し上げます。