練習日誌を手書きしている人、まだいると思う。
ノートに距離とタイムを書く。Excelに転記する。先週と比較する。あるいはStravaのアプリを開いて、スクロールして過去のデータを確認する。
悪くはない。でも非効率。
自分は226kmの準備期間中、練習データの管理にStrava API × Google Apps Script(GAS)を使った。練習が終わると、Stravaに記録されたデータが自動的にGoogleスプレッドシートに転記される。距離、タイム、心拍、ペース、高度、TSS推定値。全部自動。
週5分の入力作業がゼロになった。その5分を振り返り分析に使えるようになった。
この記事では、その仕組みの作り方を具体的に解説する。プログラミング経験がなくても、コピペで動く。
完成形のイメージ
まず完成形を見せる。Googleスプレッドシートに以下のデータが自動で記録される。
| 日付 | 種目 | 距離(km) | 時間 | 平均心拍 | 平均ペース | 獲得標高(m) | TSS推定 |
|---|---|---|---|---|---|---|---|
| 3/24 | ラン | 10.2 | 0:52:30 | 148 | 5:09/km | 45 | 62 |
| 3/23 | バイク | 80.5 | 2:45:00 | 135 | 29.3km/h | 320 | 145 |
| 3/22 | スイム | 3.0 | 1:05:00 | 125 | 1:53/100m | 0 | 55 |
さらに週次サマリーが自動生成される。
| 週 | スイム(km) | バイク(km) | ラン(km) | 合計時間 | 平均心拍 |
|---|---|---|---|---|---|
| W12 | 6.0 | 160 | 35 | 12:30 | 138 |
| W11 | 5.5 | 140 | 30 | 11:15 | 142 |
これが練習のたびに自動更新される。手入力ゼロ。
必要なもの
- Stravaアカウント(無料でOK、有料サブスク不要)
- Googleアカウント(GmailがあればOK)
- 30分の初期設定時間
それだけ。サーバーもドメインも不要。
Step 1:Strava APIアプリを作成する
StravaにはAPIが公開されていて、自分の練習データをプログラムから取得できる。
- https://www.strava.com/settings/api にアクセス
- 「APIアプリケーションを作成する」をクリック
- 以下を入力:
- アプリケーション名: 練習ログ自動化(何でもOK)
- カテゴリ: Training Analysis
- ウェブサイト: https://localhost(仮でOK)
- Authorization Callback Domain: localhost
- 作成するとClient IDとClient 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_token と refresh_token が含まれる。この2つをメモ。
Step 3:Googleスプレッドシートを準備する
- Google Driveで新規スプレッドシートを作成
- シート名を「練習ログ」に変更
- 1行目にヘッダーを入力: 日付 / 種目 / 距離(km) / 時間 / 平均心拍 / 平均ペース / 獲得標高(m) / TSS推定 / Strava URL
Step 4:GASスクリプトを設定する
- スプレッドシートで「拡張機能」→「Apps Script」を開く
- 以下のコードを全文コピーして貼り付ける
// === 設定 ===
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のトリガー機能で、毎日自動実行させる。
- Apps Scriptの左メニュー → 「トリガー」
- 「トリガーを追加」をクリック
- 設定:
- 関数: fetchActivities
- イベントのソース: 時間主導型
- タイプ: 日付ベース
- 時刻: 午前5時〜6時
- 保存
これで毎朝5時に、前日の練習データが自動でスプレッドシートに追加される。
なぜ手入力ではダメなのか
「Stravaのアプリで見れるから十分」という意見はもっともだ。
だが226kmの準備では、週単位・月単位の推移を見る必要がある。Stravaのアプリは個別のアクティビティを見るのは得意だが、「先月と今月でバイクの距離がどう変わったか」を一覧で確認するのは苦手。
スプレッドシートに全データが並んでいると、以下が一目で分かる。
- 練習量が計画通りに推移しているか
- 特定の種目が不足していないか
- 心拍数のトレンド(オーバートレーニングの兆候)
- 週ごとの負荷の波(ピリオダイゼーション通りか)
手入力だと「面倒だから今日はサボろう」が発生する。自動化すると「データは常に最新」が保証される。
まとめ
初期設定は30分。それ以降はメンテナンス不要。練習データが自動で蓄積されていく。
226kmの準備は長期戦。3ヶ月、半年の練習データが整理された状態で手元にあるかどうかで、調整期の判断精度が変わる。
30分の投資で、練習管理の質が一段上がる。
まずは無料版を試す → チェックリストLite


コメント