【GoogleMaps APIを使わずに!!】GASで住所から各種情報を取得するTips

## 背景
住所が入力されたシートから、郵便番号を生成してほしいという依頼をうける。
Googleが出しているGeocoding APIを使わないといけないかなぁと調べていると・・・Classあるじゃん!!となる。

## 本題

### Class Geocoder
[公式ドキュメント](https://developers.google.com/apps-script/reference/maps/geocoder)にあるように、Urlfetch使ってGeocoding API叩くなど不要!!

### <span style="color: #ef0606">注意</span>
使いすぎると課金対象・・・な気がします。
ちゃんと調べてないですが。
1日100件とかなら動きます。(一応、私はsleep挟んで使ってます。1秒間のリクエスト上限もあったはず。)

### サンプル
A1セルに入っている住所をGeocoder Classを使って情報を取得します。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/219427/1a656166-b1b2-7692-7d12-188b5e9ec563.png)

#### コード
```javascript
function sample_geocoder () {
  const address = SpreadsheetApp.getActiveSheet().getRange(1,1).getValue();
  var
    geocoder = Maps.newGeocoder(), // Creates a new Geocoder object.
    geocoder = geocoder.setLanguage('ja'),  // Use Japanese
    response = geocoder.geocode(address).results[0]
    json = JSON.stringify(response); // ets the approximate geographic points for a given address.
  Logger.log(json);
}// function sample_geocoder
```

#### 結果
出てきたデータを適当にフォーマッターにかけました。
JSONで帰ってくるので、あとは[Geocoding API]の仕様にあわせて必要なデータを取得しにいくだけです!

```geocode.json
{
	"plus_code": {
		"compound_code": "JPM5+45 日本、東京都目黒区",
		"global_code": "8Q7XJPM5+45"
	},
	"types": [
		"street_address"
	],
	"geometry": {
		"location": {
			"lng": 139.7079097,
			"lat": 35.63275660000001
		},
		"location_type": "ROOFTOP",
		"viewport": {
			"southwest": {
				"lat": 35.63140761970851,
				"lng": 139.7065607197085
			},
			"northeast": {
				"lng": 139.7092586802915,
				"lat": 35.63410558029151
			}
		}
	},
	"address_components": [
		{
			"types": [
				"premise"
			],
			"short_name": "３",
			"long_name": "３"
		},
		{
			"long_name": "９",
			"short_name": "９",
			"types": [
				"political",
				"sublocality",
				"sublocality_level_4"
			]
		},
		{
			"types": [
				"political",
				"sublocality",
				"sublocality_level_3"
			],
			"long_name": "３丁目",
			"short_name": "３丁目"
		},
		{
			"types": [
				"political",
				"sublocality",
				"sublocality_level_2"
			],
			"long_name": "目黒",
			"short_name": "目黒"
		},
		{
			"long_name": "目黒区",
			"short_name": "目黒区",
			"types": [
				"locality",
				"political"
			]
		},
		{
			"short_name": "東京都",
			"long_name": "東京都",
			"types": [
				"administrative_area_level_1",
				"political"
			]
		},
		{
			"types": [
				"country",
				"political"
			],
			"short_name": "JP",
			"long_name": "日本"
		},
		{
			"types": [
				"postal_code"
			],
			"long_name": "153-0063",
			"short_name": "153-0063"
		}
	],
	"formatted_address": "日本、〒153-0063 東京都目黒区目黒３丁目９−３",
	"place_id": "ChIJQ2DzCiOLGGAR3-c813QEVuY"
}
```

### 緯度,・経度を取得
response > geometry > viewport
と遡っていけばいい。

#### コード

```sample_geocoder.js
function sample_geocoder () {
  const address = SpreadsheetApp.getActiveSheet().getRange(1,1).getValue();
  var
    geocoder = Maps.newGeocoder() // Creates a new Geocoder object.
    , geocoder = geocoder.setLanguage('ja') // Use Japanese
    , response = geocoder.geocode(address).results[0]; // ets the approximate geographic points for a given address.
  Logger.log(response.geometry.location.lat + " : " + response.geometry.location.lng);
}// function sample_geocoder
```

#### 結果
緯度 : 経度 の形式で取得。
`35.6590249 : 139.703473`

### 郵便番号
response > address_components > types has "postal_code"

#### コード
配列ぐるぐる探す方法。
もう少しいい方法はないものか?

```sample_geocoder.js
function sample_geocoder () {
  const address = SpreadsheetApp.getActiveSheet().getRange(1,1).getValue();
  var
    geocoder = Maps.newGeocoder() // Creates a new Geocoder object.
    , geocoder = geocoder.setLanguage('ja') // Use Japanese
    , response = geocoder.geocode(address).results[0] // ets the approximate geographic points for a given address.
    , components = response.address_components // get address_components object
  ;
  components.forEach(function ( value ) {
    if ( value.types.indexOf('postal_code') > -1 ) {
      Logger.log(value.long_name);
      return;
    }// if
  });// forEach
}// function sample_geocoder
```

#### 結果
`150-0002`

###  住所
typesの中にも複数入っている。辛い。

#### コード
超絶ブサイクですが。
function get_data_by_type() の中身がforEachではなく、for文になっているのは、うまいこと途中抜けできなかったからです。
(勉強不足感)

```sample.js
function get_data_by_type ( components, key_type ) {
  for ( var i = 0; i < components.length; ++i ) {
    var value = components[i];    
    if ( value.types.indexOf( key_type ) > -1 ) {
      return value.long_name;
    }// if
  }// for_i
}// function get_data_by_type

function sample_geocoder () {
  const address = SpreadsheetApp.getActiveSheet().getRange(1,1).getValue();
  var
    geocoder = Maps.newGeocoder() // Creates a new Geocoder object.
    , geocoder = geocoder.setLanguage('ja') // Use Japanese
    , response = geocoder.geocode(address).results[0] // ets the approximate geographic points for a given address.
    , components = response.address_components // get address_components object
  ;
  var
    res 
     = [ 
         get_data_by_type( components, 'postal_code' )
         , get_data_by_type( components, 'country' )
         , get_data_by_type( components, 'administrative_area_level_1' )
         , get_data_by_type( components, 'locality' )
         , get_data_by_type( components, 'sublocality_level_2' )
         , get_data_by_type( components, 'sublocality_level_3' )
         , get_data_by_type( components, 'sublocality_level_4' )
       ].join(' ')
  ;
  Logger.log( res );
}// function sample_geocoder
```

#### 結果
`150-0002 日本 東京都 渋谷区 渋谷 ２丁目 ２１`