住所を地理的座標へ変換するツールを作成しました（Googleマップ＋Googleスプレッドシート＋Google Geocoding API）

# 目的
Google Apps Scriptと[Google Maps Platform](https://cloud.google.com/maps-platform/?authuser=1)の勉強のため、Googleスプレッドシートと[Google Maps Platform](https://cloud.google.com/maps-platform/?authuser=1)の[Geocoding API](https://developers.google.com/maps/documentation/geocoding/start?authuser=1)を用いて、住所を地理的座標へ変換するツールを作成してみました。

＜2019/09/27追記＞
※なお、Geocoding APIは、数千件程度～最大４万件の住所データであれば、１か月の無料枠内で遊ぶことができます。
※４万件を超えるような大量の住所データをジオコーディングする場合は、東京大学空間情報科学研究センターがオープンソースとして提供する[ジオコーダDAMS(Distributed Address Matching System）](http://newspat.csis.u-tokyo.ac.jp/geocode/modules/dams/index.php?content_id=1)等のオンプレミスな環境で実行する方法があります。

### [Geocoding API](https://developers.google.com/maps/documentation/geocoding/start?authuser=1)
- 今回は、Google Maps Platformの中でも「プレイス」に分類される「Geocoding API」を使用しています。
- Geocoding APIは、住所を地理的座標に変換したり、地理的座標から住所を特定したりできます。

### Google Apps Script
- Google Apps Scriptは、Google社が提供するJavaScriptベースのプログラミング言語であり、クラウドサーバ上で動作します。
- Gmail、Googleスプレッドシート、Googleカレンダー、Googleドライブ、Google翻訳などのGoogleが提供する数々のアプリケーション群をプログラミングにより操作可能です。

# 実行環境
この記事ではGoogle Apps Scriptを使っています。
コードを実行するためにはGoogle Maps PlatformのAPIキーが必要です。

>※Google Maps Platform APIキーの取得・発行についてはこちらを参照してください。
https://www.zenrin-datacom.net/business/gmapsapi/api_key/index.html

# 前提条件

### 住所
地理的座標に変換する住所は、道の駅１３３駅（中部地方）を対象としました。
[道の駅](http://www.mlit.go.jp/road/Michi-no-Eki/)

# 実行方法

### 入力設定

- Googleスプレッドシートに住所を入力します。
- 住所はB列に入力してください。
- A列、C列、D列の入力内容は任意です。
- シート名は「address」に変更してください。
- 実行結果はE列、F列、G列に出力されます。
<img width="620" alt="キャプチャ.PNG" src="https://qiita-image-store.s3.amazonaws.com/0/205045/f28654d2-7ca7-3cc3-71d6-100a64b6238e.png">

### 実行
- Googleスプレッドシートのツール＞スクリプトエディタを開いて、下記のソースを貼り付け、「関数を選択」を「Main」にしてスクリプトを実行してください。

- Googleスプレッドシートへのアクセス権の確認画面が出ますので許可してください。

```javascript:gas1.gs
//基本的な設定
//**********************************************************************************************
// APIKEYを設定する
var APIKEY = "APIキーを入力する" // APIキー
//**********************************************************************************************

var Address;        // 住所
var ArrAddressLst;  // 住所リスト
var LastRow;        // 最終行

//**********************************************************************************************
// Main関数
// GeocodingAPIを実行する関数
//**********************************************************************************************
function Main() {

  // 住所を設定する
  setaddress();
  
  // 戻り値を格納する配列
  var ArrRes = [];
  for (var i = 0; i <= LastRow-2; i++) {
    
    // GeocodingAPI関数による住所と緯度経度の取得
    var data = GeocodingAPI(ArrAddressLst[i][0], APIKEY);
    
    // 戻り値を配列に格納する
    ArrRes[i] = [];
    ArrRes[i][0] = data[0]; // formatted_address
    ArrRes[i][1] = data[1]; // lat
    ArrRes[i][2] = data[2]; // lng
    
  }
  
  // 結果をスプレッドシートに出力する
  var bk = SpreadsheetApp.getActiveSpreadsheet();  // アクティブなスプレッドシートを取得する
  var sh = bk.getSheetByName('address');           // addressシートを取得する
  
  for (var i = 0; i <= LastRow-2; i++) {
    // 値をセルに入力する
    sh.getRange(i + 2, 5).setValue(ArrRes[i][0]);  // formatted_address
    sh.getRange(i + 2, 6).setValue(ArrRes[i][1]);  // lat
    sh.getRange(i + 2, 7).setValue(ArrRes[i][2]);  // lng
  }
  
}

//**********************************************************************************************
// 住所を設定する関数
//**********************************************************************************************
function setaddress() {
  // addressシートの内容を配列に格納する
  var bk = SpreadsheetApp.getActiveSpreadsheet();             // アクティブなスプレッドシートを取得する
  var sh = bk.getSheetByName('address');                      // addressシートを取得する
  LastRow = sh.getLastRow();                                  // 最終行を取得する
  // var colLst = sh.getLastColumn();                            // 最終列を取得する
  
  Logger.log(LastRow);
  
  // データを配列に格納する
  // Sheetオブジェクト.getRange(行番号, 列番号, 行数, 列数)
  ArrAddressLst = sh.getRange(2, 2, LastRow-1, 1).getValues();

  Logger.log(ArrAddressLst);
  
}

//**********************************************************************************************
// GeocodingAPI関数
//**********************************************************************************************
function GeocodingAPI(Address, APIKEY){
  // URLを作成する
  var url = "https://maps.googleapis.com/maps/api/geocode/json?language=ja" + 
            "&address=" + Address + 
            "&sensor=false" +
            "&key=" + APIKEY;

  Logger.log(url);
  
  // HTTPリクエストを行う
  var res  = UrlFetchApp.fetch(url,{muteHttpExceptions:true});
  Logger.log(res); 
  
  // HTTPレスポンスを文字列として取得、JSON形式の文字列を解析してオブジェクトとして返す
  var json = JSON.parse(res.getContentText()); 
  Logger.log(json);
  
  if (json["status"] == "OK") {
    var json_formatted_address = json["results"][0]["formatted_address"];
    var json_lat = json["results"][0]["geometry"]["location"]["lat"];
    var json_lng = json["results"][0]["geometry"]["location"]["lng"];
    
    // 「日本、」「郵便番号」を除外
    var formatted_address = json_formatted_address.split(' ');
    
    return [formatted_address[1],json_lat,json_lng];
    
  }
}
```

# 実行結果
- 実行結果はE列、F列、G列に出力されます。
- E列～G列がGeocodingAPIによりHTTPレスポンスとして受け取った結果になります。
- E列が住所（formatted_address）になります（formatted_addressに含まれる「日本」や「郵便番号」は除外しています）。
- F列が緯度（lat）、G列（lng）が経度になります。
<img width="881" alt="キャプチャ2.PNG" src="https://qiita-image-store.s3.amazonaws.com/0/205045/b9262f99-cb91-077d-4613-818f35afb32a.png">


# 留意事項
- [Geocoding APIは、1か月$200分の無料クレジットの範囲では最大40,000呼び出し]((https://cloud.google.com/maps-platform/pricing/sheet/?authuser=1)**)
- **※無料枠を超えてAPIを使用すると課金されますのでご注意ください(>_<)**

# 参考書
[詳解! GoogleAppsScript完全入門 ~GoogleApps & G Suiteの最新プログラミングガイド~](https://www.amazon.co.jp/%E8%A9%B3%E8%A7%A3-GoogleAppsScript%E5%AE%8C%E5%85%A8%E5%85%A5%E9%96%80-GoogleApps-G-Suite%E3%81%AE%E6%9C%80%E6%96%B0%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0%E3%82%AC%E3%82%A4%E3%83%89/dp/4798053767)
[Developer Guide（Geocoding API）](https://developers.google.com/maps/documentation/geocoding/start?authuser=1)