| name | yamareco |
| description | ユーザの登山履歴・各山行のタイム・ペース、および登山計画 (予定行程) をヤマレコ (yamareco.com) から取得する手順。登山計画の所要時間予測や、過去実績からのペース倍率の集計、ヤマレコに登録済みの計画の予定行程・距離・累積標高の確認を求められた際に使う。 山行リスト・計画リストは API、個別山行および個別計画の詳細は公開設定のもののみ HTML から抽出する。 |
ヤマレコ情報取得
ユーザの登山履歴・各山行のタイム・ペースを取得する手順。
情報
山行リスト取得
curl -s 'https://api.yamareco.com/api/v1/getReclist/user/{userId}/{page}' \
--header 'Accept: application/json'
- pathname の
{userId} はヤマレコユーザ ID (数値)。プロフィールページ URL https://www.yamareco.com/modules/yamareco/userinfo-{userId}-prof.html の userinfo- と -prof の間の数値 (例: userinfo-1005182-prof.html なら 1005182)。不明ならユーザに確認する
- pathname の
{page} はページ番号 (1 始まり)。母集合を揃えるには page=1 から辿る。終端を過ぎると reclist が空配列ではなく reclist キー自体が無い {"err":1,"errcode":"NODATA"} が返る。終端判定は reclist キーの有無で行い、errcode 文字列値には依存しない (計画リストも終端で同じ NODATA を返すため、文字列で見分けようとすると取り違える)
- レスポンスの
reclist[].rec_id が個別山行の ID
reclist[].permission.guest が "1" ならゲスト閲覧可、"0" なら非公開。集計時は guest="1" の山行のみ対象とし、"0" は除外して継続する (どうしても必要なら公開設定をユーザに依頼する)
reclist[].place/start/end/area などで概要把握可能
reclist[].page_url に詳細ページの HTML URL (後述)
個別山行の詳細取得
GET /api/v1/getRec/{rec_id} は OAuth 認証が必要で、未認証だと {"err":1,"message":"App does not have a valid scope."} が返る。
現状は API では詳細取れない。HTML から抽出する。
HTML から抽出する手順
公開設定 (permission.guest=1) の山行のみ取得可能。
curl -s -A "Mozilla/5.0" \
"https://www.yamareco.com/modules/yamareco/detail-{rec_id}.html" \
-o "/tmp/yamareco-{rec_id}.html"
iconv -f EUC-JP -t UTF-8//IGNORE "/tmp/yamareco-{rec_id}.html" > "/tmp/yamareco-{rec_id}-utf8.html"
複数山行を扱う場合も、各 rec_id ごとに上記の取得・変換・抽出を完結させてから次の rec_id へ進む。{rec_id} を含むパスを使えば取り違えが起きない。
- WebFetch ツールはなぜか 403 を返すので curl 直叩きが確実
- 文字コードは EUC-JP。iconv での変換必須 (しないと grep が日本語を拾えない)。不正バイトで変換が途中停止し内容が欠落するのを防ぐため
UTF-8//IGNORE を付ける (実際に一部の山行ページで illegal input sequence が起きる)
抽出ポイント
UTF-8 変換後の HTML を Grep する。
| 項目 | パターン |
|---|
| 山行時間 | class="time1">[0-9:]+ |
| 休憩時間 | class="time2">[0-9:]+ |
| 合計時間 | class="time3">[0-9:]+ |
| 距離・登り・下り | font-weight:bold;font-size:18px;">[0-9.,]+</span>(km|m) |
| ペース区分(参考) | pace[1-4]">[^<]+(とても速い / 速い / 標準 等、表記は倍率帯で変わる) |
| ペース倍率(範囲) | pace-num.{1,150} 内の font-en">[0-9.]+(下限・上限の2値) |
time1/time2/time3 は HTML 内に複数マッチがあるので最初の 1 件を採用すること (コースタイム表示用と日付表示用が混在)。
距離・登り・下りは同一パターンで 3 値が連続マッチする。HTML 上の出現順に距離 → 登り → 下りが対応する。登り・下りが 1000 以上だと 1,747 のように桁区切りカンマが入るので、パターンは [0-9.,]+ でカンマを含めて拾う([0-9.]+ だと取りこぼして 3 値に満たず、正常データを誤って構造変化と判定する)。数値化する際はカンマを除去する。マッチ数が 3 でない場合は構造変化とみなし、後述の 0 件時と同様に処理を止めて報告する。
抽出結果の検証
各抽出の直後にサニティチェックを行う。推測で値を埋めない。
- 時刻は
^[0-9]{1,2}:[0-9]{2}$、距離・標高は正の数値であることを確認する。
- 必須項目 (時刻 time1〜3/距離・登り・下り/
pace-num の倍率) で期待するマッチが0 件のときは HTML 構造が変わった可能性が高い。値を捏造せず、処理を止めて構造変化を疑い、ユーザに報告する。一方、ペース区分ラベル pace[1-4] は参考情報なので、0 件でも欠落として扱い処理を継続する (捏造しない)。
- iconv 変換後、日本語 (例: ペース区分の「速い」等) が grep で拾えるか 1 度確認する。拾えない場合は元の文字コードが EUC-JP でない可能性がある。
- ペース倍率は
pace-num 内に下限・上限の 2 値が出る。2 値揃わない場合は範囲表記の構造変化を疑う。
- 距離・登り・下りはカンマ除去後に正の数値となることを確認する。
ペース倍率の読み方
ヤマレコの「らくルート」標準コースタイムを 1.0 としたときの倍率。pace-num は単一値ではなく下限〜上限の範囲で出力される (font-en が 2 値、区切りは 〜 = ~)。
**範囲は 1 値に畳まない。**下限・上限の両方を保持してユーザにそのまま範囲で伝え、状況 (体調・天候・荷物・予備時間) に応じてどの値を採るかはユーザに選ばせる。下限に丸めると倍率を低く (= 速く) 見積もって所要時間を短く出すため、後述「楽観しすぎるな」と矛盾する。中点・上限を skill 側で決め打ちするのも同様に避ける。
区分の早見表は次のとおり (半開区間。下限以上・上限未満で全域を被覆し、境界値の帰属が一意)。
- 0.6 未満: とても速い
- 0.6 以上 0.7 未満: 速い〜とても速い
- 0.7 以上 0.9 未満: 速い
- 0.9 以上 1.1 未満: 普通
- 1.1 以上: ゆっくり (ヤマレコのペース区分の「遅い」に相当)
倍率が範囲なので、区分も下限・上限それぞれで引き、またがる場合は両区分を併記して報告する。区分名自体に「〜」を含むものがあるため「〜」で単純連結せず、側を明示する (例: 範囲[0.60 〜 0.70]なら「下限 0.60 は速い〜とても速い、上限 0.70 は速い」)。抽出パターン pace[1-4] の文字列ラベル (とても速い/速い/標準等、表記は倍率帯で変わる) は参考情報で、上の 5 区分とは対応させない。ラベル文言が上の区分名と食い違っても気にしない (別系統)。報告に載せる場合は「参考ラベル」等の別欄にし、5 区分の判定と混在させない (載せなくてもよい)。
ユーザの過去実績を集めれば、未経験ルートの所要時間を標準 CT × 倍率で予測できる。倍率が範囲なので予測も範囲で出す。集計は次の規則で行う。
- 母集合:
getReclist を page=1 から辿り、permission.guest="1" の山行を対象とする。直近 10 件程度を目安とし、季節・山域が偏らないよう選ぶ。ユーザが件数を明示した場合はそちらを優先し、目安との乖離が信頼度に影響する (少数・偏りがある) 場合はその旨を注記する。10 件は明確な上限ではなく、多少超えても偏りがなければ全件使ってよい (恣意的に間引かない)。倍率を抽出できた有効件数が 3 件に満たない場合は page を進めて補充する (上限の目安 5 ページ/50 件。届かなければ信頼度が低い旨を明示)。
- 倍率の採取: 各山行の HTML から「ペース倍率」(
pace-num 内の下限・上限の 2 値) を抽出する。抽出できない山行は母集合から除外する。
- 集計: 下限の単純平均と上限の単純平均をそれぞれ出し、[平均下限 〜 平均上限]の範囲で示す。1 値に畳まない。最低 3 件揃わない場合は予測の信頼度が低い旨を明示する。ちょうど 3 件のときも最低ラインであり、目安 (10 件程度) との乖離注記を必ず付ける。途中敗退・ルートロスト等で極端な外れ値となった山行は、理由を添えて除外してよい。
登山計画リスト取得
ユーザがヤマレコに登録済みの登山計画の一覧を取得する。
curl -s 'https://api.yamareco.com/api/v1/getPlanlist/user/{userId}/{page}' \
--header 'Accept: application/json'
- pathname の
{userId}/{page} は山行リストと同じ (ユーザ ID と 1 始まりのページ番号)。終端を過ぎると planlist キー自体が無い {"err":1,"errcode":"NODATA"} が返る。山行リストと同じく終端判定は planlist キーの有無で行い、errcode 文字列値には依存しない (記録リストと終端レスポンスが同形なので、NODATA 等の文字列で見分けない)
- レスポンスの
planlist[].plan_id が個別計画の ID
- 公開フラグは山行と極性が逆。山行は
permission.guest="1" が公開だが、計画は planlist[].private が "0" で公開、"1" で非公開 (OpenAPI の PlanSummary 準拠)。取得対象は private="0" のみとし、"1" は除外して継続する
planlist[].place/start/end/days/area/genre で概要把握可能
planlist[].nodate が "1" の計画は日程未定で、start/end/days は意味を持たない
planlist[].page_url に詳細ページの HTML URL (後述)
個別計画の詳細取得
GET /api/v1/getPlan/{plan_id} は山行詳細の getRec と同じく OAuth 認証が必要で、未認証だと App does not have a valid scope. が返る。
計画詳細も API では取れない。HTML から抽出する。
HTML から抽出する手順
公開設定 (private="0") の計画のみ取得可能。URL は山行と別モジュール (yr_plan) なので注意する。
curl -s -A "Mozilla/5.0" \
"https://www.yamareco.com/modules/yr_plan/detail-{plan_id}.html" \
-o "/tmp/yamareco-plan-{plan_id}.html"
iconv -f EUC-JP -t UTF-8//IGNORE "/tmp/yamareco-plan-{plan_id}.html" > "/tmp/yamareco-plan-{plan_id}-utf8.html"
注意点は山行 HTML と同じ。 WebFetch は 403、 EUC-JP 変換必須、 plan_id でパスを一意化する。
抽出ポイント
計画 HTML の構造は山行詳細ページと別物。山行側の実績時間 time1/time2/time3 は計画ページには無い (計画は実績ではないため)。pace-num 倍率は計画ページにもあるが意味が違う。山行の pace-num は実際に出た実績倍率の範囲、計画の pace-num は計画作成時にユーザが設定した予定倍率の単一値で、行動予定の時刻はこの予定倍率で算出されている (後述)。混同しないこと。
距離・累積標高は <dl> の <dt class="..."> で項目を示し、値はその次行の <dd> に入る。実 HTML では dt と dd が別の行に分かれているので、1 行で dt ... dd をまとめて grep すると 0 件になる。dt にマッチさせてから後続行の dd を拾うこと (例: grep -A1 で dt の次行を見る、または grep -ozP 等で改行をまたいで取得する)。
| 項目 | dt (項目行) | 次行の dd (値) |
|---|
| 距離 | <dt class="distance">距離</dt> | <dd>[0-9.,]+<span>km |
| 上り (累積標高) | <dt class="up">上り</dt> | <dd>[0-9.,]+<span>m |
| 下り (累積標高) | <dt class="down">下り</dt> | <dd>[0-9.,]+<span>m |
計画タイム (コースタイムの合計) と行動予定 (通過予定時刻列) を取得する。計画ページには新旧 2 つのレイアウトがあり、どちらが使われるかはページごとに異なる。両方を試し、片方が無いだけで「未入力」と断じない。
コースタイムの合計 (補正の入力に使う計画タイム) は次のように取得する。
- 新レイアウト:
record-detail-content-time-block-head の totaltime 内に、<dt>山行</dt><dd class="time1">9:45</dd>/<dt>休憩</dt><dd class="time2">0:00</dd>/<dt>合計</dt><dd class="time3">9:45</dd> の形で直接入る (記録ページと同じ time1/time2/time3 クラス)。補正にはこの合計 (time3、行動だけなら time1) を計画タイムとして使う。端点の時刻差を手計算するより正確。なお同じ totaltime 構造で距離・登り・下りも dd class="time2" で出るため、time2 を広域 grep すると休憩時間と距離が混ざる。山行/休憩/合計 の dt ラベルや totaltime 領域に絞って拾う。
- 旧レイアウト:
totaltime の合計が無い。後述の行動予定の通過時刻列から、最初 (出発) と最後 (下山) の時刻差で行程の幅を出す (端点差は休憩込みで粗い近似)。
行動予定 (通過予定時刻列) は次のように取得する。
- 新レイアウト:
record-detail-content-time-block-timelline 内に <div class="item ..."> が地点順に並び、1 item = 1 地点である。item 内の <div class="name"> が地点名、<div class="time1">HH:MM</div> が通過予定時刻。時刻だけ拾うと地点との対応が示せないので、item 単位で name と time1 を組にして抽出する (どちらも値は開きタグの次行以降にある)。name の中身はリンク付き (<a> 入り) とプレーンテキストの 2 形態があるため、閉じタグまでを取って内部タグを剥がしてから trim する。往復・周回計画では同名地点が正当に重複するので、出現順を保持し重複を除去しない。item class はページ後方の別文脈 (地図商品欄等) にも出現するため、まず timelline の親コンテナの範囲を切り出してからその内側でマッチする (ファイル全体から <div class="item" を拾わない)。item ブロックの切り方は、コンテナ内を item の開きタグで split し、各断片から最初の name と time1 を取る形でよい。
- 旧レイアウト:
record-detail-content-time-text の <div> 内に 地点名 23:00 → 01:08 次の地点 → … → 08:58 地点名 (下山) の形でインラインに並ぶ (区切りは → = →)。
最初の時刻が出発、最後の時刻が下山予定で、日をまたぐ計画は時刻が一周する点に注意する。いずれのレイアウトも値は開きタグの次行以降にあり、距離・累積標高と同じく行をまたいで取得する (1 行 grep では空振りする)。開きタグにマッチさせて後続行を拾うか、開きタグから閉じタグまでの行範囲を sed 等で切り出す。grep -ozP を使うなら改行を含む文字クラス ([\s\S] 等) でないと拾えない。
計画の予定倍率は class="record-detail-content-pace" の領域内、pace-num の font-en に単一値で入る (記録のような下限・上限の範囲ではない)。ラベルは label-pace pace[1-4] (標準等、参考)。これは計画作成時にユーザが設定した倍率で、行動予定の時刻はこの倍率で計算されている。多くは 1.0 (標準) だがユーザが変更でき計画ごとに異なるので、必ず抽出して確認し 1.0 と決め打ちしない。
| 項目 | パターン |
|---|
| 計画の予定倍率 | pace-num の数行先の font-en">[0-9.]+ (単一値) |
| ペース区分ラベル | label-pace pace[1-4]">[^<]+ (標準 等、参考) |
pace-num と font-en は別行に分かれる場合と同一行に収まる場合の両方がある。行をまたぐ取得 (grep -A3 や -ozP) は同一行も包含するので、常に行またぎ前提で拾えば両形態に対応できる。
抽出結果の検証
- 距離・上り・下りはカンマ除去後に正の数値であることを確認する。上り・下りは
1,425 のように桁区切りカンマが入るので [0-9.,]+ で拾い、数値化時にカンマを除去する。
- 距離・上り・下りが 0 件のときは、まず行をまたぐ取得 (
grep -A1/-ozP) で拾えているかを確認する。dt と dd が別行なので 1 行 grep では正常な HTML でも 0 件になり、これを構造変化と取り違えやすい。行をまたいでも 0 件のときに限り HTML 構造が変わった可能性が高いとみなし、値を捏造せず処理を止めて構造変化を疑い、報告する。
- 行動予定は新旧レイアウトの両方 (
record-detail-content-time-block-timelline と record-detail-content-time-text) を確認し、どちらにも時刻列が無いときのみコースタイム未入力とみなす。片方の class が無いだけで「未入力」と断じない。未入力なら捏造せず「予定行程は未入力」として扱う。class 名は <style> 内の CSS 定義にも出現するため、存在判定は単純な出現カウントでなく開きタグ形 (class="..." を含むタグ) でマッチする。
- 計画の予定倍率は
pace-num 内に単一値で出る。下限・上限の 2 値が出たら記録ページと取り違えている。値が取れないときは 1.0 と仮定せず、未取得として扱い後述の補正では安全側 (遅い前提) に倒す。
- iconv 変換後、日本語 (地点名等) が grep で拾えるか 1 度確認する。拾えない場合は元の文字コードが EUC-JP でない可能性がある。
登山計画への活用
ユーザがヤマレコに計画を登録済みなら、「登山計画リスト取得」「個別計画の詳細取得」でその計画の予定行程・距離・累積標高・予定倍率を直接取得できる。
計画の行動予定の時刻は、その計画の予定倍率 (pace-num。多くは 1.0 = 標準 CT だが計画ごとに確認する) で算出されている。予定倍率は「標準的な歩き手」の想定であって、ユーザ自身の実力ではない。ユーザの実力倍率 (記録側で実測される範囲) と食い違う分だけ、実際の所要時間は計画とずれる。この差を埋めて現実的なタイムを伝える。
未経験ルートの予測 (標準 CT から)
- 過去の山行タイムからペース倍率を集計 (下限・上限の範囲で。集計規則は「ペース倍率の読み方」に従う)
- ヤマレコや登山地図アプリで標準 CT を確認。登録済み計画があれば、その行動予定 (予定倍率込み) と距離・累積標高をそのまま使える
- 平均倍率の範囲 (下限〜上限) を標準 CT に掛け、予測タイムを範囲で算出 (1 値に畳まない)
- 休憩を 1〜1.5 時間上乗せして合計時間とする (合計も範囲のまま。範囲同士の合算は最小+最小・最大+最大で端点を取る)
- 標高・距離・累積標高がユーザ実績の最大値を超える場合は楽観しすぎるな
登録済み計画をユーザの実力で補正する
計画の行動予定タイムを、ユーザの実力に合わせた現実的タイムへ補正する。安全に直結する。下記ガードレールを必ず守る。
補正式は次のとおり (範囲は範囲のまま、1 値に畳まない)。
現実タイムの範囲 = 計画タイム × (ユーザ実力倍率の範囲 [下限 〜 上限] / 計画の予定倍率)
- 計画の予定倍率が 1.0 なら、現実タイムの範囲 = 計画タイム ×[実力下限 〜 実力上限]。
- 計画の予定倍率が 1.0 でない (ユーザが速いペースを設定済み等) 場合、行動予定は既にそのペースで前倒しされている。予定倍率で割って標準 CT 基準に戻してから実力倍率を掛ける。割り忘れると二重補正になる。
DANGER ガードレール。倍率を小さく報告して入山し事故った場合の被害は甚大なので、下振れ方向への丸めは禁止する。
- 倍率を機械的に直近 N 件の単純平均で 1 値に決めない。範囲を保持し、判断は安全側 (大きい倍率 = 遅い = 長い時間) に寄せる。
- 次の要因がある場合は倍率を上方 (上限側、必要ならさらに上) に補正する。複数該当すれば重ねて効かせる。
- 前回登山からのブランク。長いほど体力が落ちているので、ブランクが大きいほど上方へ。
- 期間・季節・条件。盛夏の高温、積雪期、複数日行程、悪天など消耗が大きい条件。
- 規模。計画の距離・累積標高・行動時間がユーザ直近実績の最大を超える (手順 5 と接続)。
- データの代表性。倍率の母集合が古い (長ブランク)、山域・季節が計画と違う、有効件数が 3 件未満。信頼度が低い旨を明示し安全側に上げる。
- 報告は必ず範囲で出し、推奨は安全側 (上限) を主に置く。休憩 1〜1.5 時間と予備時間の上乗せは省かない。
- 機械的に出した倍率は素案にすぎない。最終的にどの倍率を採るかは、ブランク・体調・天候・荷物・予備時間を踏まえてユーザに選ばせる。skill 側で下限に決め打ちして短い時間を提示しない。
- 倍率や所要時間を推測で埋めない。実力倍率の母集合が足りない、計画の予定倍率が取れない等で確度が低いときは、その旨を明示し安全側 (遅い前提) で伝える。
注意
- 詳細を取りたい山行は事前にユーザにヤマレコの公開設定を依頼
- HTML 構造は変わる可能性あり。抽出失敗したらこの skill 更新