momota.txt

hello, hello, hello, how low?

Google Apps Script でサーバレスな為替レート取得クローラをつくる

Google Apps Script (GAS) は、Google が提供する JavaScript プラットフォームで、Google apps (Calendar, Docs, Drive, Gmail, Sheets, and Slides) に対して処理する JavaScript を簡単に書ける。 Excel マクロのすごい版みたいな感覚。

このスクリプトからHTTP GETリクエストを出したり、受け付けたりできる。

今回は、この GAS を使って、無料の Web クローラをサーバレスでつくってみる。

処理の流れ

  1. GAS から為替レート API をたたく
  2. 取得した為替レートデータを Google Sheets へ出力する
  3. 上記を1分間隔で実行する。

1. GAS から為替レート API をたたく

為替レート API の確認

API は https://www.gaitameonline.com/rateaj/getrate を利用する。 ここへ HTTP GET すると以下のような JSON フォーマットが返ってくる。 (整形済み)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
{
  quotes=[
    {
      high=1.9196,
      low=1.9162,
      ask=1.9212,
      bid=1.9195,
      currencyPairCode=GBPNZD,
      open=1.9167
    },
    {
      high=82.83,
      low=82.35,
      ask=82.41,
      bid=82.36,
      currencyPairCode=CADJPY,
      open=82.76
    },
    // ... (snip) ...

JSON の quotes は各通貨ペアの配列になっており、各要素に high, low, … などのフィールドがある構造になっている。

robots.txt には特に言及されていないが、非常識なアクセスはしないように注意。

GAS の作成

Apps Script のメニューから + 新規スクリプト をクリックすると、新規プロジェクトが立ち上がる。 プロジェクト名やスクリプト名は適当に変更する。 (デフォルト Code.gs)

GAS で API をたたく処理は以下のように書ける。

1
2
3
4
5
6
7
8
9
10
11
function callExchangeAPI() {
    var now      = new Date(),
        url      = "https://www.gaitameonline.com/rateaj/getrate",
        response = UrlFetchApp.fetch(url),
        content  = response.getContentText(),
        fx       = JSON.parse(content);

    fx.date = now;
    Logger.log(fx);
    return fx;
}

UrlFetchApp.fetch(url) で API の URL をたたきにいける。 fx.date = now で、取得した JSON に取得日時フィールド date を足している。

上記をコピペして実行する (▶ボタンを押す) と初回実行時には以下のような確認ダイアログがでるので Review Permissions を押して許可する。

01_notice_initial_run

その後、Choose an account画面で自分のアカウントを選ぶと、確認画面 YOUR-PROJECT-NAME wants to access your Google Account が出てくるので ALLOW ボタンを押す。そうすると実行できる。

Logger.log(fx) 部分でログ出力しているので、メニュー View > Logs からログ出力できていることが確認できる。 ログは以下のように出力される。

1
2
[18-06-24 23:24:06:486 PDT] {date=Mon Jun 25 15:24:06 GMT+09:00 2018, quotes=[{high=1.9224, low=1.9162, ask=1.9223, bid=1.9206, currencyPairCode=GBPNZD, open=1.9167}, {high=82.83, low=82.22, ask=82.45, bid=82.40, currencyPairCode=CADJPY, open=82.76}, {high=1.7870, low=1.7817, ask=1.7855, bid=1.7846, currencyPairCode=GBPAUD, open=1.7817},
... snip ...

2. 取得した為替レートデータを Google Sheets へ出力する

取得した為替レートを以下のように Google sheetsに出力する。

03_sheet

シートの 1 行目はヘッダ、列の定義は以下。通貨ペア種別すべての Ask や Bid などを取得したタイミングごとに1行で表現する。

1
date, currencyPairCode1, high1, low1, ask1, bid1, open1, currencyPairCode2, high2, ...

まずは、出力先にあたる Google sheets を新規作成し、その URL をコピーする。

個別の URL をコードに埋め込みたくないので、Script properties に値をセットしてそれをコードの中から利用する。

GAS のメニュー File > Project properties から Script properties タブへ移動する。 + Add row のリンクから行をエントリーする。 Property に SHEET_URL、Value に先程コピーした Google sheets の URLを登録する。 登録するURL は https://docs.google.com/spreadsheets/d/xxxxxxxxxxxxxxxxxxxxx/edit のような形式。

上述した Script properties から値を参照して、Sheet オブジェクトを取得する処理は以下。

1
2
3
4
5
6
7
8
9
10
11
12
  function() {
    if(this.getSheet.sheet) { return this.getSheet.sheet; }

    var SHEET_URL = PropertiesService.getScriptProperties().getProperty('SHEET_URL');
    if (!SHEET_URL) {
      throw 'You should set "SHEET_URL" property from [File] > [Project properties] > [Script properties]';
    }

    var sheets = SpreadsheetApp.openByUrl(SHEET_URL);
    this.getSheet.sheet = sheets.getActiveSheet();
    return this.getSheet.sheet;
  }

API から取得してきた JSON データをシートに出力する。

シートに対して入力するには、sheet.getRange(row, column).setValue(something) のようにシートの行 (row) と列 (column) を指定して setValue を呼べば良い。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
  function(ex_json) {
    var sheet = this.getSheet();

    // データ追加行 (Sheetの最終行 + 1) を取得する
    var last_row = sheet.getLastRow() + 1;

    var col = 1;
    sheet.getRange(last_row, col++).setValue(ex_json.date);

    for each(var quote in ex_json.quotes) {
      sheet.getRange(last_row, col++).setValue(quote.currencyPairCode);
      sheet.getRange(last_row, col++).setValue(quote.high);
      sheet.getRange(last_row, col++).setValue(quote.low);
      sheet.getRange(last_row, col++).setValue(quote.ask);
      sheet.getRange(last_row, col++).setValue(quote.bid);
      sheet.getRange(last_row, col++).setValue(quote.open);
    }
  }

上記をまとめると以下。 以下をコピペして実行する (▶ボタンを押す) と Google sheets に為替データが挿入される。 初回実行時に権限の確認ダイアログがでると思うが許可してあげる。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
// Main
function scrapeExchangeToSheet() {
  var ex_json = exchange.callExchangeAPI();
  exchange.writeSheets(ex_json);
}

var exchange = {
  getSheet: function() {
    if(this.getSheet.sheet) { return this.getSheet.sheet; }

    var SHEET_URL = PropertiesService.getScriptProperties().getProperty('SHEET_URL');
    if (!SHEET_URL) {
      throw 'You should set "SHEET_URL" property from [File] > [Project properties] > [Script properties]';
    }

    var sheets = SpreadsheetApp.openByUrl(SHEET_URL);
    this.getSheet.sheet = sheets.getActiveSheet();
    return this.getSheet.sheet;
  },

  // call exchange API
  callExchangeAPI: function() {
    var now      = new Date(),
        url      = "https://www.gaitameonline.com/rateaj/getrate",
        response = UrlFetchApp.fetch(url),
        content  = response.getContentText(),
        fx       = JSON.parse(content);

    fx.date = now;
    return fx;
  },

  // Write exchange data (JSON) to the Google Sheet
  writeSheets: function(ex_json) {
    var sheet = this.getSheet();

    // get last row to add exchange data
    var last_row = sheet.getLastRow() + 1;

    var col = 1;
    sheet.getRange(last_row, col++).setValue(ex_json.date);

    for each(var quote in ex_json.quotes) {
      sheet.getRange(last_row, col++).setValue(quote.currencyPairCode);
      sheet.getRange(last_row, col++).setValue(quote.high);
      sheet.getRange(last_row, col++).setValue(quote.low);
      sheet.getRange(last_row, col++).setValue(quote.ask);
      sheet.getRange(last_row, col++).setValue(quote.bid);
      sheet.getRange(last_row, col++).setValue(quote.open);
    }
  }
}

3. 上記を1分間隔で実行する。

上記の処理を定期的に実行する。

時計マークのアイコンをクリックする。もしくは、メニュー Edit > Current project's trigger を選択する。 そうするとダイアログが出てくるので、No triggers set up. Click here to add one now. をクリックする。

Run にはメイン処理の scrapeExchangeToSheet, Events には好きな起動時間を設定できる。 ここでは1分間隔で実行するため、Time-driven : Minutes timer: Every minute を選択する。

1分間隔で Google sheets にデータが挿入されていることが確認できる。

Comments