日本郵便から全国郵便番号と住所を取得し、開いているスプレッドシートに出力する

# Google App Scriptで作ろう その① 日本郵便からZIPをダウンロード、解凍、必要なデータをSpreadSheetに出力

## やりたいこと
1. 日本郵便からzipファイルをダウンロードする
2. ZIPを解凍
3. ZIPからCSVデータをロード
4. SpreadSheetに出力

## どんなコードになるのか
```javascript

// 現状、こちらは使わない
var JAPAN_POST_ZIP_URLS = [
  "https://www.post.japanpost.jp/zipcode/dl/kogaki/zip/01hokkai.zip",
  "https://www.post.japanpost.jp/zipcode/dl/kogaki/zip/02aomori.zip",
  "https://www.post.japanpost.jp/zipcode/dl/kogaki/zip/03iwate.zip",
  "https://www.post.japanpost.jp/zipcode/dl/kogaki/zip/04miyagi.zip",
  "https://www.post.japanpost.jp/zipcode/dl/kogaki/zip/05akita.zip",
  "https://www.post.japanpost.jp/zipcode/dl/kogaki/zip/06yamaga.zip",
  "https://www.post.japanpost.jp/zipcode/dl/kogaki/zip/07fukush.zip",
  "https://www.post.japanpost.jp/zipcode/dl/kogaki/zip/08ibarak.zip",
  "https://www.post.japanpost.jp/zipcode/dl/kogaki/zip/09tochig.zip",
  "https://www.post.japanpost.jp/zipcode/dl/kogaki/zip/10gumma.zip",
  "https://www.post.japanpost.jp/zipcode/dl/kogaki/zip/11saitam.zip",
  "https://www.post.japanpost.jp/zipcode/dl/kogaki/zip/12chiba.zip",
  "https://www.post.japanpost.jp/zipcode/dl/kogaki/zip/13tokyo.zip",
  "https://www.post.japanpost.jp/zipcode/dl/kogaki/zip/14kanaga.zip",
  "https://www.post.japanpost.jp/zipcode/dl/kogaki/zip/15niigat.zip",
  "https://www.post.japanpost.jp/zipcode/dl/kogaki/zip/16toyama.zip",
  "https://www.post.japanpost.jp/zipcode/dl/kogaki/zip/17ishika.zip",
  "https://www.post.japanpost.jp/zipcode/dl/kogaki/zip/18fukui.zip",
  "https://www.post.japanpost.jp/zipcode/dl/kogaki/zip/19yamana.zip",
  "https://www.post.japanpost.jp/zipcode/dl/kogaki/zip/20nagano.zip",
  "https://www.post.japanpost.jp/zipcode/dl/kogaki/zip/21gifu.zip",
  "https://www.post.japanpost.jp/zipcode/dl/kogaki/zip/22shizuo.zip",
  "https://www.post.japanpost.jp/zipcode/dl/kogaki/zip/23aichi.zip",
  "https://www.post.japanpost.jp/zipcode/dl/kogaki/zip/24mie.zip",
  "https://www.post.japanpost.jp/zipcode/dl/kogaki/zip/25shiga.zip",
  "https://www.post.japanpost.jp/zipcode/dl/kogaki/zip/26kyouto.zip",
  "https://www.post.japanpost.jp/zipcode/dl/kogaki/zip/27osaka.zip",
  "https://www.post.japanpost.jp/zipcode/dl/kogaki/zip/28hyogo.zip",
  "https://www.post.japanpost.jp/zipcode/dl/kogaki/zip/29nara.zip",
  "https://www.post.japanpost.jp/zipcode/dl/kogaki/zip/30wakaya.zip",
  "https://www.post.japanpost.jp/zipcode/dl/kogaki/zip/31tottor.zip",
  "https://www.post.japanpost.jp/zipcode/dl/kogaki/zip/32shiman.zip",
  "https://www.post.japanpost.jp/zipcode/dl/kogaki/zip/33okayam.zip",
  "https://www.post.japanpost.jp/zipcode/dl/kogaki/zip/34hirosh.zip",
  "https://www.post.japanpost.jp/zipcode/dl/kogaki/zip/35yamagu.zip",
  "https://www.post.japanpost.jp/zipcode/dl/kogaki/zip/36tokush.zip",
  "https://www.post.japanpost.jp/zipcode/dl/kogaki/zip/37kagawa.zip",
  "https://www.post.japanpost.jp/zipcode/dl/kogaki/zip/38ehime.zip",
  "https://www.post.japanpost.jp/zipcode/dl/kogaki/zip/39kochi.zip",
  "https://www.post.japanpost.jp/zipcode/dl/kogaki/zip/40fukuok.zip",
  "https://www.post.japanpost.jp/zipcode/dl/kogaki/zip/41saga.zip",
  "https://www.post.japanpost.jp/zipcode/dl/kogaki/zip/42nagasa.zip",
  "https://www.post.japanpost.jp/zipcode/dl/kogaki/zip/43kumamo.zip",
  "https://www.post.japanpost.jp/zipcode/dl/kogaki/zip/44oita.zip",
  "https://www.post.japanpost.jp/zipcode/dl/kogaki/zip/45miyaza.zip",
  "https://www.post.japanpost.jp/zipcode/dl/kogaki/zip/46kagosh.zip",
  "https://www.post.japanpost.jp/zipcode/dl/kogaki/zip/47okinaw.zip"
];

// 全国の郵便番号アーカイブ
var ALL_ZIP_MASTER_URL  = "https://www.post.japanpost.jp/zipcode/dl/kogaki/zip/ken_all.zip";
var ALL_ZIP_CONTENT_OPTION = {contentType: "text/csv", charSet: "Shift-JIS"};

// ロード中のスプレッドシート
var OPEN_SPREAD_SHEET = SpreadsheetApp.getActiveSpreadsheet();
var SET_VALUE_SHEET_NAME = "Worksheet";

// 全国の郵便番号アーカイブのダウンロード
function download_all_zip_master() {
  // fileのダウンロード＆解凍
  var blob = download_zip(ALL_ZIP_MASTER_URL, ALL_ZIP_CONTENT_OPTION);
  if (blob === null)
    return;
  Logger.log(blob.getDataAsString(ALL_ZIP_CONTENT_OPTION['charSet']));

  // 結果がなければ処理中断させる
  if (blob.length === 0)
    return;

  // CSVロード
  var csvDatas = Utilities.parseCsv(blob.getDataAsString(ALL_ZIP_CONTENT_OPTION['charSet']));

  var filteredCsvDatas = [];
  for(row in csvDatas.slice(1)) {
    var csvRow = csvDatas[row];
    filteredCsvDatas.push(
      [
        csvRow[2],                         // 郵便番号
        csvRow[4] + csvRow[5],             // 住所カナ
        csvRow[6] + csvRow[7] + csvRow[8]  // 住所漢字
      ]
    );
  }

  // スプレッドシートに出力
  OPEN_SPREAD_SHEET.getSheetByName(SET_VALUE_SHEET_NAME).getRange(1, 1, filteredCsvDatas.length, filteredCsvDatas[0].length).setValues(filteredCsvDatas);
}
  
// ZIPファイルダウンロード&解凍
function download_zip(url, exOption) {
  // リクエストパラメータ
  var options = {
  }
  // Download
  var response = UrlFetchApp.fetch(url, options);
  if (response.getResponseCode() !== 200)
    return null;

  var blob = response.getBlob();
  // Content-Type set
  blob.setContentTypeFromExtension();
  var data_blob = Utilities.unzip(blob);

  if (exOption !== null) 
    data_blob = Utilities.newBlob("", exOption['contentType'], data_blob[0].getName()).setDataFromString(data_blob[0].getDataAsString(exOption['charSet']), exOption['charSet']);

  return data_blob;
}
```

## パフォーマンスについて

### スプレッドシート出力処理について

```javascript

  var filteredCsvDatas = [];
  for(row in csvDatas.slice(1)) {
    var csvRow = csvDatas[row];
    filteredCsvDatas.push(
      [
        csvRow[2],                         // 郵便番号
        csvRow[4] + csvRow[5],             // 住所カナ
        csvRow[6] + csvRow[7] + csvRow[8]  // 住所漢字
      ]
    );
  }

  // スプレッドシートに出力
  OPEN_SPREAD_SHEET.getSheetByName('Worksheet').getRange(1, 1, filteredCsvDatas.length, filteredCsvDatas[0].length).setValues(filteredCsvDatas);
```

上記と、下記の違いは、Rangeをあらかじめ指定し、二次元配列をまとめて展開してしまうか、一行ずつfetchして出力するかであるが、無論、下記の方が処理が遅い

```javascript

  // スプレッドシートに出力
  var start_col, start_row = 1;
  for (row in filteredCsvDatas) {
    start_col = 1;
    for (s_row in filteredCsvDatas[row]) {
      OPEN_SPREAD_SHEET.getSheetByName('Worksheet').getRange(start_row, start_col).setValue(filteredCsvDatas[row][s_row]);
      start_col++;
    }
    start_row++;
  }
```