金額を送るだけ！GAS×スプシで作る家計簿LINEボット

# はじめに
「スプシで家計簿を管理しているが、毎回スプシに入力するのが面倒くさい！
　LINEから入力できるようにならないか？」

と知人から依頼を受けたのでLINEボットを作りました

この記事では、LINEとGoogle Apps Script（GAS）を使って、簡単に支出記録ができる家計簿ボットを作る方法を紹介します。

# この家計簿ボットでできること
- LINEで金額（例：300）を送信すると、日付と金額がスプレッドシートに記録される
- 記録されたデータから、当月平均支出額と支出予測額が返信される

![456B9454-CC1D-4BEF-AFD9-CE08F940D51F.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2704675/f9c73ea9-441f-4921-9890-3fbd0f412f99.jpeg)


データはGoogleスプレッドシートに蓄積されるので、後から自由にグラフ化・分析も可能です

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2704675/b3b9fe33-5066-42b8-ab66-1c9b157ce048.png)

# 使用した技術
- Google Apps Script（GAS）：サーバーレスでLINEのWebhookを処理
- LINE Messaging API：ユーザーのメッセージを取得し、返信する
- Google スプレッドシート：支出データを保存するデータベースとして使用

# 全体の仕組み
1. ユーザーがLINEで「金額」を送信
1. GASがそのメッセージを受け取る（Webhook）
1. スプレッドシートに日時と金額を記録
1. 同時に、当月の平均支出と支出予測を計算
1. 結果をLINEに自動返信

# STEP 1：LINEボットの準備
## LINEボットの作成
[LINE Official Account Manager](https://manager.line.biz/)からLINE公式アカウントを作成します。

![スクリーンショット 2025-04-12 15.01.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2704675/5b73bf0a-d115-45b3-8811-ac75a672fe29.png)

公式ページに詳しい手順が説明されています。

https://www.lycbiz.com/jp/manual/OfficialAccountManager/new_account/?list=7171

## Messaging APIの有効化

GASでメッセージの送受信を行うため、Messaging APIを有効化します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2704675/d6d08ee6-6f3d-46e0-99b8-b1496ed6b3c6.png)

こちらも公式ページに詳しい手順が説明されています。

https://www.lycbiz.com/jp/manual/OfficialAccountManager/account-settings_messaging_api/?list=7171

## 応答設定

応答設定から「Webhook」を有効化、「応答メッセージ」を無効化します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2704675/21a5bdb7-91d6-449e-ab81-95c8df855c92.png)


## チャンネルアクセストークンの発行

[LINE Developersコンソール](https://developers.line.biz/ja/)から、Messaging API設定を選択します。

![スクリーンショット 2025-04-12 15.23.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2704675/982392cb-16b4-415e-9897-085d43091570.png)

ページ下部でチャンネルアクセストークンを発行できます。このチャンネルアクセストークンをメモしておきます。

![スクリーンショット 2025-04-12 15.24.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2704675/9cf49aec-36a2-4832-92b7-96e93b663f6f.png)

# STEP 2：スプレッドシートの準備

[新規スプレッドシートを作成](https://docs.google.com/spreadsheets/u/0/create)し、「ログ」という名前でシートを作成します。

A列にtimestamp、B列にmonth、C列にpriceを記載します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2704675/978eb633-9251-4d08-9b98-4ee49d37cbeb.png)

# STEP 3：GASのコード実装
## Scriptの作成
Apps Scriptを選択し、GASエディタで以下のスクリプトを作成します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2704675/7356cd75-cee1-4e44-a9e6-338184bf38d7.png)

```Javascript:GASコード
const sheet = SpreadsheetApp.openById('スプシIDを入力する').getSheetByName('ログ');

function doPost(e) {
  const json = JSON.parse(e.postData.contents);

  const userMessage = json.events[0].message.text;
  const replyToken = json.events[0].replyToken;

  // 数字でなければ返信して終了
  if (isNaN(userMessage)) {
    replyToUser(replyToken, "数字を送ってください🙇‍♂️");
    return;
  }

  const timestamp = new Date();
  const month = Utilities.formatDate(timestamp, 'Asia/Tokyo', 'yyyy-MM');
  const year = timestamp.getFullYear() - 2000; // 2025 → 25年
  const monthLabel = `${year}年${timestamp.getMonth() + 1}月`;

  // データの記録
  sheet.appendRow([timestamp, month, Number(userMessage)]);

  // 今月の平均支出額を算出、支出合計の予測
  const result = predictThisMonthExpense();

  replyToUser(replyToken, `¥${userMessage}を記録しました📒\n\n${monthLabel}の平均支出: ¥${result.averagePerDay}\n${monthLabel}の支出予測: ¥${result.predictedTotal}`);
}

// 返信する
function replyToUser(replyToken, message) {
  const url = 'https://api.line.me/v2/bot/message/reply';
  const accessToken = PropertiesService.getScriptProperties().getProperty('LINE_TOKEN'); // LINEのチャネルアクセストークン

  const headers = {
    'Content-Type': 'application/json',
    'Authorization': 'Bearer ' + accessToken
  };

  const postData = {
    replyToken: replyToken,
    messages: [
      {
        type: 'text',
        text: message
      }
    ]
  };

  const options = {
    'method': 'post',
    'headers': headers,
    'payload': JSON.stringify(postData)
  };

  UrlFetchApp.fetch(url, options);
}

// 今月の平均支出額を算出し、支出合計を予測する
function predictThisMonthExpense() {
  const data = sheet.getDataRange().getValues();

  const now = new Date();
  const currentMonth = Utilities.formatDate(now, 'Asia/Tokyo', 'yyyy-MM'); // 今月のyyyy-MM
  const currentDay = now.getDate(); // 今日の日付

  // ログシートから今月の支出を抽出
  const rowsThisMonth = data.slice(1).filter(row => {
    const rowMonth = Utilities.formatDate(new Date(row[0]), 'Asia/Tokyo', 'yyyy-MM');
    return rowMonth === currentMonth;
  });

  const total = rowsThisMonth.reduce((sum, row) => sum + Number(row[2]), 0); // 今月の支出合計
  const daysInMonth = new Date(now.getFullYear(), now.getMonth() + 1, 0).getDate(); // 今月の日数

  // 平均支出 × 今月の日数 で予想を出す
  const averagePerDay = Math.round(total / currentDay) || 0; // 平均支出額
  const predictedTotal = Math.round(averagePerDay * daysInMonth); // 予測支出額

  return {
    averagePerDay: averagePerDay,
    predictedTotal: predictedTotal
  };
}
```

## スクリプト プロパティの設定

GASの設定からスクリプト プロパティを作成し、
プロパティに`LINE_TOKEN`、値にSTEP1で発行したチャンネルアクセストークンを入力し、保存します

![スクリーンショット 2025-04-12 15.20.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2704675/60fb950e-4a54-4551-bb67-8dfbd9d07344.png)

## デプロイ

「デプロイ」>「新しいデプロイ」を選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2704675/7594d39b-fd17-4f3d-adf5-688a07a9190e.png)

「ウェブアプリ」を選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2704675/c5fdce07-8874-41c3-8e31-f78539fd78a8.png)

アクセスできるユーザー「全員」を選択し、「デプロイ」をクリックします。

![スクリーンショット 2025-04-12 15.29.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2704675/76be921e-4656-4243-8d4a-3b75e9825132.png)

表示されたウェブアプリのURLをコピーします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2704675/31b4ae4a-8980-4c9f-b140-956a30d32734.png)

## Webhook URLの設定

[LINE Official Account Manager](https://manager.line.biz/)のMessaging API設定画面から、ウェブアプリのURLを入力して保存します。

![スクリーンショット 2025-04-12 15.32.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2704675/e5a424ce-f8e8-43e5-b825-e6cd3ae88189.png)


# まとめ

以上の手順でLINEボットは完成です！

下記のようにやり取りできます。

誤って記録してしまった場合はマイナスの値を送信することで、打ち消せます。
また、数字以外が送られてきた場合は、エラーメッセージが表示されます。

![LINE_capture_766132952.170025.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2704675/d268d945-ad61-461c-b558-85b601c54947.jpeg)