練習日誌をまだ手書きしてるトライアスリートへ — Strava API × GASで全自動化した話

練習日誌をまだ手書きしてるトライアスリートへ — Strava API × GASで全自動化した話 Data & Tech
練習日誌をまだ手書きしてるトライアスリートへ — Strava API × GASで全自動化した話

練習日誌を手書きしている人、まだいると思う。

ノートに距離とタイムを書く。Excelに転記する。先週と比較する。あるいはStravaのアプリを開いて、スクロールして過去のデータを確認する。

悪くはない。でも非効率。

自分は226kmの準備期間中、練習データの管理にStrava API × Google Apps Script(GAS)を使った。練習が終わると、Stravaに記録されたデータが自動的にGoogleスプレッドシートに転記される。距離、タイム、心拍、ペース、高度、TSS推定値。全部自動。

週5分の入力作業がゼロになった。その5分を振り返り分析に使えるようになった。

この記事では、その仕組みの作り方を具体的に解説する。プログラミング経験がなくても、コピペで動く。

完成形のイメージ

まず完成形を見せる。Googleスプレッドシートに以下のデータが自動で記録される。

日付種目距離(km)時間平均心拍平均ペース獲得標高(m)TSS推定
3/24ラン10.20:52:301485:09/km4562
3/23バイク80.52:45:0013529.3km/h320145
3/22スイム3.01:05:001251:53/100m055

さらに週次サマリーが自動生成される。

スイム(km)バイク(km)ラン(km)合計時間平均心拍
W126.01603512:30138
W115.51403011:15142

これが練習のたびに自動更新される。手入力ゼロ。

必要なもの

  1. Stravaアカウント(無料でOK、有料サブスク不要)
  2. Googleアカウント(GmailがあればOK)
  3. 30分の初期設定時間

それだけ。サーバーもドメインも不要。

Step 1:Strava APIアプリを作成する

StravaにはAPIが公開されていて、自分の練習データをプログラムから取得できる。

  1. https://www.strava.com/settings/api にアクセス
  2. 「APIアプリケーションを作成する」をクリック
  3. 以下を入力:
    • アプリケーション名: 練習ログ自動化(何でもOK)
    • カテゴリ: Training Analysis
    • ウェブサイト: https://localhost(仮でOK)
    • Authorization Callback Domain: localhost
  4. 作成するとClient IDClient Secretが表示される。これをメモしておく

Step 2:アクセストークンを取得する

Strava APIを使うにはアクセストークンが必要。以下の手順で取得する。

ブラウザで以下のURLにアクセスする(Client IDを自分のものに置き換え)。

https://www.strava.com/oauth/authorize?client_id=あなたのClientID&response_type=code&redirect_uri=http://localhost&scope=activity:read_all&approval_prompt=auto

「許可する」をクリックすると、localhostにリダイレクトされる。URLの中に code=xxxxxxxxxxxx が含まれているので、このコードをコピーする。

次に、このコードを使ってアクセストークンを取得する。

curl -X POST https://www.strava.com/api/v3/oauth/token \
  -d client_id=あなたのClientID \
  -d client_secret=あなたのClientSecret \
  -d code=さっきコピーしたコード \
  -d grant_type=authorization_code

レスポンスに access_tokenrefresh_token が含まれる。この2つをメモ

Step 3:Googleスプレッドシートを準備する

  1. Google Driveで新規スプレッドシートを作成
  2. シート名を「練習ログ」に変更
  3. 1行目にヘッダーを入力: 日付 / 種目 / 距離(km) / 時間 / 平均心拍 / 平均ペース / 獲得標高(m) / TSS推定 / Strava URL

Step 4:GASスクリプトを設定する

  1. スプレッドシートで「拡張機能」→「Apps Script」を開く
  2. 以下のコードを全文コピーして貼り付ける
// === 設定 ===
const CLIENT_ID = 'あなたのClientID';
const CLIENT_SECRET = 'あなたのClientSecret';
const REFRESH_TOKEN = 'あなたのRefreshToken';

function getAccessToken() {
  const response = UrlFetchApp.fetch('https://www.strava.com/api/v3/oauth/token', {
    method: 'post',
    payload: {
      client_id: CLIENT_ID,
      client_secret: CLIENT_SECRET,
      refresh_token: REFRESH_TOKEN,
      grant_type: 'refresh_token'
    }
  });
  return JSON.parse(response.getContentText()).access_token;
}

function fetchActivities() {
  const token = getAccessToken();
  const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('練習ログ');
  const response = UrlFetchApp.fetch(
    'https://www.strava.com/api/v3/athlete/activities?per_page=30',
    { headers: { Authorization: 'Bearer ' + token } }
  );
  const activities = JSON.parse(response.getContentText());
  const existingIds = sheet.getRange(2, 9, Math.max(sheet.getLastRow() - 1, 1), 1)
    .getValues().flat().filter(v => v);

  activities.forEach(a => {
    const stravaUrl = 'https://www.strava.com/activities/' + a.id;
    if (existingIds.includes(stravaUrl)) return;
    const type = convertType(a.type);
    const distance = (a.distance / 1000).toFixed(1);
    const time = formatTime(a.moving_time);
    const hr = a.average_heartrate || '';
    const pace = calcPace(a.type, a.distance, a.moving_time);
    const elevation = Math.round(a.total_elevation_gain);
    const tss = estimateTSS(a.moving_time, a.average_heartrate);
    const date = Utilities.formatDate(new Date(a.start_date_local), 'Asia/Tokyo', 'M/d');
    sheet.appendRow([date, type, distance, time, hr, pace, elevation, tss, stravaUrl]);
  });
  const dataRange = sheet.getRange(2, 1, sheet.getLastRow() - 1, 9);
  dataRange.sort({ column: 1, ascending: false });
}

function convertType(type) {
  const map = { Run: 'ラン', Ride: 'バイク', Swim: 'スイム', Walk: 'ウォーク' };
  return map[type] || type;
}

function formatTime(seconds) {
  const h = Math.floor(seconds / 3600);
  const m = Math.floor((seconds % 3600) / 60);
  const s = seconds % 60;
  return h + ':' + String(m).padStart(2, '0') + ':' + String(s).padStart(2, '0');
}

function calcPace(type, distance, time) {
  if (type === 'Run') {
    const paceSeconds = time / (distance / 1000);
    const min = Math.floor(paceSeconds / 60);
    const sec = Math.round(paceSeconds % 60);
    return min + ':' + String(sec).padStart(2, '0') + '/km';
  } else if (type === 'Ride') {
    return ((distance / 1000) / (time / 3600)).toFixed(1) + 'km/h';
  } else if (type === 'Swim') {
    const pace100 = time / (distance / 100);
    const min = Math.floor(pace100 / 60);
    const sec = Math.round(pace100 % 60);
    return min + ':' + String(sec).padStart(2, '0') + '/100m';
  }
  return '';
}

function estimateTSS(seconds, hr) {
  if (!hr) return '';
  const hours = seconds / 3600;
  const intensity = hr / 180;
  return Math.round(hours * intensity * intensity * 100);
}

Step 5:自動実行を設定する

GASのトリガー機能で、毎日自動実行させる。

  1. Apps Scriptの左メニュー → 「トリガー」
  2. 「トリガーを追加」をクリック
  3. 設定:
    • 関数: fetchActivities
    • イベントのソース: 時間主導型
    • タイプ: 日付ベース
    • 時刻: 午前5時〜6時
  4. 保存

これで毎朝5時に、前日の練習データが自動でスプレッドシートに追加される。

なぜ手入力ではダメなのか

「Stravaのアプリで見れるから十分」という意見はもっともだ。

だが226kmの準備では、週単位・月単位の推移を見る必要がある。Stravaのアプリは個別のアクティビティを見るのは得意だが、「先月と今月でバイクの距離がどう変わったか」を一覧で確認するのは苦手。

スプレッドシートに全データが並んでいると、以下が一目で分かる。

  • 練習量が計画通りに推移しているか
  • 特定の種目が不足していないか
  • 心拍数のトレンド(オーバートレーニングの兆候)
  • 週ごとの負荷の波(ピリオダイゼーション通りか)

手入力だと「面倒だから今日はサボろう」が発生する。自動化すると「データは常に最新」が保証される。

まとめ

初期設定は30分。それ以降はメンテナンス不要。練習データが自動で蓄積されていく。

226kmの準備は長期戦。3ヶ月、半年の練習データが整理された状態で手元にあるかどうかで、調整期の判断精度が変わる。

30分の投資で、練習管理の質が一段上がる。

完走テンプレPro(¥2,980)

練習データの蓄積があると、より精度の高い目標設定ができる。当日タイムライン付き。

詳しく見る →

まずは無料版を試す → チェックリストLite

コメント

タイトルとURLをコピーしました