LoginSignup
2
3

FlaskでAPIを作って、受け取ったデータをGoogleスプレッドシートに書き出す

Last updated at Posted at 2024-03-31

つくるもの

Pythonで取得したデータを順次GASに返却し、GAS側で受け取ったデータをスプレッドシートに書き込む。
GASには時間制限があるため、開始位置と終了位置を指定し、細かく区切って返却するようにする。

  • Flask側アプリ
    • Flaskで作成
    • Herokuで公開
    • 処理内容:開始位置と終了位置を受け取りデータ(今回は仮データ)を返す
  • GAS側
    • 実行時、開始位置と終了位置をFlaskアプリに投げ、受け取ったJSONデータをGoogleスプレッドシートに書き込む
    • 一回の実行で10ずつデータを受け取り、50受け取るまで繰り返し実行する

環境

  • MAC
  • Python 3.11.3
  • Flask 3.0.2

Flask側アプリの作成

flaskのinstall

pip install Flask

開発フォルダの作成

mkdir my-test-api
cd my-test-api

APIの作成

pythonファイルのファイル名は任意

main.py
from flask import Flask, request, jsonify
import os

app = Flask(__name__)

@app.route('/process', methods=['POST'])
def process_data():
    # POSTリクエストからstart_numberとend_numberの値を取得
    start_number = int(request.form['start_number'])
    end_number = int(request.form['end_number'])
    
    results = []
    # start_numberとend_numberの範囲で処理を繰り返す
    for i in range(start_number, end_number + 1):
        # ここでstart_numberとend_numberを使って何らかの処理を行う
        result = f"実行結果{i}"
        # 結果をリストに追加
        results.append([i, result])
    
    # 処理結果をJSON形式で返す
    return jsonify(results)

if __name__ == '__main__':
    app.run(host="0.0.0.0", port=int(os.environ.get("PORT", 5000)))

ローカル環境でのテスト

先ほど作成したFlaskアプリケーションを実行する

Python main.py

テスト用アプリの作成

先ほど作ったFlaskアプリケーションをテストするためのFlaskアプリケーションを作成する。

test.py
import requests,json

url = 'http://127.0.0.1:5000/process'
data = {'start_number': 10, 'end_number': 20}
response = requests.post(url, data=data)

# エスケープされたJSON文字列をデコードしてリストに変換
decoded_list = json.loads(response.text)

print(decoded_list)

テスト用アプリケーションの実行

先ほどのFlaskアプリケーションを起動したまま、別ターミナルで実行する

Python test.py

実行結果

$ python test.py
[[10, '実行結果10'], [11, '実行結果11'], [12, '実行結果12'], [13, '実行結果13'], [14, '実行結果14'], [15, '実行結果15'], [16, '実行結果16'], [17, '実行結果17'], [18, '実行結果18'], [19, '実行結果19'], [20, '実行結果20']]

FlaskアプリケーションをHerokuにデプロイする

runtime.text

herokuでサポートしているPythonのバージョンを確認する。

echo "python-3.11.3" > runtime.txt

Procfile

install gunicorn
echo web: gunicorn main:app --log-file=- > Procfile

requirements.txt

pip freeze > requirements.txt

gunicornの行が出力されていることを確認。

ファイルの作成完了

my_test_app/
│
├── main.py
├── Procfile
├── requirements.txt
└── runtime.txt

heroku CLI インストール

brew tap heroku/brew && brew install heroku

heroku ログイン

heroku login

アプリ作成

アプリ名は他と被らないような任意のサイト名を設定する。

heroku create アプリ名
(例)これだと被るので作成できない
heroku create my-test-api

リモートブランチ作成

my-test-apiの部分は作成したアプリ名に置き換え

heroku git:remote -a my-test-api

Herokuにmainブランチをpushする

git push heroku main

デプロイ後の動作確認

先ほど作成したtest.pyを流用する

test.py
import requests,json

url = '[★この部分をデプロイ後のURLに差し替え]/process'
data = {'start_number': 10, 'end_number': 20}
response = requests.post(url, data=data)

# エスケープされたJSON文字列をデコードしてリストに変換
decoded_list = json.loads(response.text)

print(decoded_list)

実行

Python test.py

実行結果

$ python test.py
[[10, '実行結果10'], [11, '実行結果11'], [12, '実行結果12'], [13, '実行結果13'], [14, '実行結果14'], [15, '実行結果15'], [16, '実行結果16'], [17, '実行結果17'], [18, '実行結果18'], [19, '実行結果19'], [20, '実行結果20']]

GAS側アプリの作成

前準備:スプレッドシートの作成

作成したGoogleスプレッドシートのURLからIDを取得する

https://docs.google.com/spreadsheets/d/[この部分がID]/edit#gid=0

シート名を結果出力に変更

GASアプリケーションの作成

GAS から「新しいプロジェクト」を作成する。

var url = "[デプロイしたURL]/process";

function myFunction() {
  // スプレッドシートのシート名を指定します
  var sheetName = "結果出力";
  // スプレッドシートを取得します
  var ss = SpreadsheetApp.openById("[スプレッドシートのID]");
  var sheet = ss.getSheetByName(sheetName);

  // スクリプトプロパティから最後に処理した値を取得
  var startNumberStr =
    PropertiesService.getScriptProperties().getProperty("start_number");
  var endNumberStr =
    PropertiesService.getScriptProperties().getProperty("end_number");

  // 値がない場合は初期値を設定
  if (!startNumberStr || !endNumberStr) {
    // スプレッドシートのデータをすべてクリアします
    sheet.clear();

    startNumber = 1;
    endNumber = 10;
  } else {
    startNumber = parseInt(startNumberStr);
    endNumber = parseInt(endNumberStr);
  }

  var payload = {
    start_number: startNumber.toString(),
    end_number: endNumber.toString(),
  };

  var options = {
    method: "post",
    payload: payload,
  };

  var response = UrlFetchApp.fetch(url, options);

  // 取得したデータを処理する(ここではログに出力する)
  Logger.log(response); // 取得したデータをログに出力
  // データをシートに書き込む
  let json = JSON.parse(response)
  var row = startNumber;
  json.forEach(function(rowData) {
    rowData.forEach(function(cellData, col) {
      sheet.getRange(row, col + 1).setValue(cellData);
    });
    row++;
  });

  // 次の範囲をセットアップ
  startNumber += 10;
  endNumber += 10;

  // スクリプトプロパティに次回処理する値を保存
  PropertiesService.getScriptProperties().setProperty(
    "start_number",
    startNumber
  );
  PropertiesService.getScriptProperties().setProperty("end_number", endNumber);

  // 100まで取得が終わったらトリガーを削除して処理を終了する
  if (endNumber > 50) {
    ScriptApp.getProjectTriggers().forEach(function (trigger) {
      ScriptApp.deleteTrigger(trigger);
    });
    // ScriptProperties を削除します
    PropertiesService.getScriptProperties().deleteAllProperties();
  } else {
    // 5秒後に自身を再実行するトリガーを設定
    ScriptApp.newTrigger("myFunction").timeBased().after(5000).create();
  }
}

GASアプリケーションの実行

スクリーンショット 2024-03-31 22.49.10.png

スクリーンショット 2024-03-31 22.45.45.png

トリガーとスクリプトプロパティがセットされていることを確認

トリガー

スクリーンショット 2024-03-31 22.50.39.png

スクリプトプロパティ

スクリーンショット 2024-03-31 22.50.51.png

最終的な実行結果

待っていれば、順次実行されるはず。
5回すべて実行完了するまでに7分程度かかっているようです。

スクリーンショット 2024-03-31 23.05.59.png

スクリーンショット 2024-03-31 23.06.52.png

終わりに

Flaskアプリケーション側の処理を変えれば、さまざまな応用ができると思います。

2
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
3