Google Apps Scriptで場所名から住所や緯度経度を取得する

## はじめに
Google Apps ScriptでGoogle Mapsの[Geocoding API](https://developers.google.com/maps/documentation/geocoding?hl=ja)を使用して、場所の名前から住所と緯度経度を取得してみたいと思います。

以下のようなスプレッドシートの状態から、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3637890/2bfaff78-c0fe-ef3b-db89-51162367c293.png)

以下の状態にすることを目指します。
※使用した場所名は山手線の駅名です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3637890/5a651e50-970c-6a78-3b53-3a922c940d96.png)

## 実装内容
### ジオコーディングを実施する関数

```javascript
function geocode(place) {
  const res = Maps.newGeocoder().setLanguage('ja').geocode(place);
  if (res.results.length !== 0) {
    const fullAddr = res.results[0].formatted_address;
    const location = res.results[0].geometry.location;

    // 「日本、〒」を削除し、郵便番号と住所を分割
    const addrParts = fullAddr.replace('日本、〒', '').split(' ');
    const postalCode = addrParts[0];
    const address = addrParts.slice(1).join(' ');

    return [postalCode, address, location];
  } else {
    return [null, null, { lng: null, lat: null }];
  }
}
```
引数として場所名の文字列を受け取っています。
レスポンスで受け取る内容（res.results[0]）は以下のような内容となります。
```
{ geometry: 
   { viewport: { northeast: [Object], southwest: [Object] },
     location: { lat: 35.68123620000001, lng: 139.7671248 },
     location_type: 'ROOFTOP' },
  plus_code: 
   { compound_code: 'MQJ8+FR 日本、東京都千代田区',
     global_code: '8Q7XMQJ8+FR' },
  types: 
   [ 'establishment',
     'point_of_interest',
     'subway_station',
     'train_station',
     'transit_station' ],
  formatted_address: '日本、〒100-0005 東京都千代田区丸の内１丁目９ 東京駅',
  partial_match: true,
  place_id: 'ChIJC3Cf2PuLGGAROO00ukl8JwA',
  address_components: 
   [ { long_name: '東京駅', short_name: '東京駅', types: [Object] },
     { long_name: '９', short_name: '９', types: [Object] },
     { types: [Object], long_name: '１丁目', short_name: '１丁目' },
     { types: [Object], short_name: '丸の内', long_name: '丸の内' },
     { long_name: '千代田区', short_name: '千代田区', types: [Object] },
     { long_name: '東京都', types: [Object], short_name: '東京都' },
     { long_name: '日本', short_name: 'JP', types: [Object] },
     { long_name: '100-0005',
       short_name: '100-0005',
       types: [Object] } ] }
```

この中geometry.locationから緯度経度を取得しています。
住所と郵便番号は、今回はformatted_addressの文字列から抽出してみました。

### メイン処理
スプレッドシートから場所名を取得して先ほどの関数を実行し、スプレッドシートに結果を書き込む処理です。

```javascript
function main() {
  // スプレッドシートから場所名を取得
  const res = Sheets.Spreadsheets.Values.batchGet(
    SpreadsheetApp.getActive().getId(), // スプレッドシートID
    { ranges: ['シート1!A2:A'] } // 取得したい範囲
  );
  
  const valueRanges = res.valueRanges || [];
  const places = valueRanges[0].values;

  // ジオコーディングを実施
  let addrs = [];
  places.forEach((place, index) => {
    const [postalCode, addr, location] = geocode(place);
    console.log(location);
    addrs.push([postalCode, addr, location.lng, location.lat]);
  });

  // スプレッドシートに結果を書き込む
  Sheets.Spreadsheets.Values.batchUpdate(
    {
      valueInputOption: 'USER_ENTERED',
      data: [
        {
          range: 'シート1!B2',
          values: addrs
        },
      ]
    },
    SpreadsheetApp.getActive().getId()
  );
}
```

スプレッドシートから値を読み取る、書き込む時にはgetValuesやsetValuesを使うことも多いと思いますが、今回はSheets APIのbatchGet、batchUpdateを使用してみています。
今回くらいの件数であればさほど差は出ないですが、件数が多くなるとSheets APIを使用する方が処理速度の向上に繋がるためです。

以下の記事などを参考にしています。

https://qiita.com/yosoyalumno/items/f28f6e90a0cf9d9ff1d9

:::note warn
GASでSheets APIを使用するためには、[「サービスを追加」からSheets APIを追加](https://qiita.com/yosoyalumno/items/f28f6e90a0cf9d9ff1d9#gas%E3%81%8B%E3%82%89sheetsapi%E3%82%92%E5%88%A9%E7%94%A8%E3%81%99%E3%82%8B%E3%81%9F%E3%82%81%E3%81%AE%E6%BA%96%E5%82%99)してください。
:::

これでスプレッドシートのA列に場所名を入力してmain関数を実行すると、以下のような結果が得られると思います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3637890/5a651e50-970c-6a78-3b53-3a922c940d96.png)

## まとめ
場所の名前から住所や緯度経度が取得できるのは便利ですね。今度はマップ上に可視化も試してみたいと思います。

## 参考

https://qiita.com/STSHISHO/items/c2a68989d74db4725112