調査レポート: STVサイトからメイボンソワ選曲データを取得する方法 (#919)
概要
STVのサイトにある選曲リストページからメイボンソワの放送データ(放送日・オンエア楽曲)を収集するための方法を調査した。
対象URL: https://www.stv.jp/radio/bonsoir/senkyoku/index.html
調査結果
1. サイト構造の確認
URL形式
- 最新回:
https://www.stv.jp/radio/bonsoir/senkyoku/index.html - 過去回:
https://www.stv.jp/radio/bonsoir/senkyoku/{ID}.html(例:d1tpn60000003m32.html)- IDはランダムな英数字形式(連番ではない)
コンテンツ構造
放送日: 2026年5月9日(土)
コーナー名: 稲場愛香のまなかん♡ボンソワ
パーソナリティ: 稲場愛香
M1「熱狂バイレ」(稲場愛香)
M2「Hanabira」(3House)
M3「雫に恋して」(indigo la End)
M4「Die With a Smile」(レディーガガ&ブルーノマーズ)
楽曲情報は <p> タグにプレーンテキストで記載される(構造化マークアップなし)。
JavaScriptレンダリング
不要(静的HTML)。radiko.jpのタイムフリー再生ボタンはJavaScript必須だが、楽曲リスト取得には影響しない。
ページネーション
index.htmlには最新1〜2回分へのリンクのみ掲載- 全過去回の一覧ページは未確認
- 各ページに「過去の放送回へのリンク」が含まれる可能性あり(リンクをたどって遡及する方式で対応可能)
2. 取得可能なフィールド
| フィールド | 例 | 備考 |
|---|---|---|
| 放送日 | 2026年5月9日(土) |
テキスト形式 → Date 変換が必要 |
| コーナー名 | 稲場愛香のまなかん♡ボンソワ |
パーソナリティ名を含む |
| パーソナリティ | 稲場愛香 |
コーナー名から抽出可能 |
| トラック番号 | M1, M2, … |
正規表現で抽出 |
| 曲名 | 熱狂バイレ |
鍵括弧内のテキスト |
| アーティスト名 | 稲場愛香 |
丸括弧内のテキスト |
通常4曲(M1〜M4)。
3. robots.txt の確認
User-agent: *
明示的な Disallow 指定は確認されなかった。 ただし、ページフッターに以下の著作権注記がある:
「無断で複写・複製・転載・加工などを行うと、著作権に基づく処罰の対象となる場合があります」
データ収集自体は問題ないが、収集データの表示・転載は注意が必要。 個人利用目的(本アプリ内での表示)の範囲であれば許容範囲と判断する。
4. スクレイピングの可否
| 項目 | 判定 | 理由 |
|---|---|---|
| 技術的可否 | ✅ 可能 | 静的HTML、JavaScriptレンダリング不要 |
| 法的可否 | ✅ 問題なし | robots.txtに明示的禁止なし |
| クローリング負荷 | ✅ 低 | 番組は週1回放送のため頻繁なpollingは不要 |
5. 既存スキーマへのマッピング
| 収集データ | スキーマ | フィールド | 対応状況 |
|---|---|---|---|
| 放送日 | RadioEpisode |
date |
✅ 対応可能 |
| パーソナリティ | RadioMember |
memberId |
✅ 対応可能(メンバーIDへの変換が必要) |
| 日直 | RadioMember |
isDayDuty |
⚠️ 概念なし(コーナー担当者として isDayDuty=false で格納) |
| 曲名 | RadioOnairSong |
songTitle |
✅ 対応可能 |
| トラック番号 | RadioOnairSong |
trackOrder |
✅ 対応可能 |
| アーティスト名 | RadioOnairSong |
フィールド未存在 | ❌ スキーマ拡張が必要 |
課題: RadioOnairSong にアーティスト名フィールドがない。
モーニング女学院(#918)の場合、楽曲はモーニング娘。の楽曲なので trackId で紐付けられる。
しかしメイボンソワは外部アーティストの楽曲が多く(例: いきものがかり、ヤングスキニー等)、
trackId が存在しないためアーティスト名を保持する必要がある。
RadioOnairSong に artistName VARCHAR(255) カラムの追加を推奨する(#922 データ設計書で詳細化)。
推奨収集手法
静的HTMLスクレイピング(fetch + 正規表現)を使用する。
選定理由
- JavaScript レンダリングが不要で実装コストが低い
- 既存の HTML 解析パターン(各種スクリプト)を流用できる
- 外部APIへの依存なく安定して収集可能
- コスト無料
実装方針
collect-bonsoir-songs.ts
→ index.html を fetch で取得
→ 最新放送回の楽曲データを正規表現でパース
→ 未収集の過去回リンクを再帰的にたどる
→ RadioEpisode / RadioMember / RadioOnairSong に格納
→ GitHub Actions で毎週土曜午前に実行(放送翌朝)
パース方針(暫定)
// 楽曲行: M1「タイトル」(アーティスト)
const songPattern = /M(\d+)「(.+?)」((.+?))/g;
// 放送日: 2026年5月9日(土) → Date
const datePattern = /(\d{4})年(\d{1,2})月(\d{1,2})日/;
制約・リスク
- STVのHTML構造が変更された場合にパース処理の修正が必要
- 過去回の全アーカイブへのリンク体系が不明(一覧ページがなければ遡及取得が困難)
- アーティスト名の表記揺れへの対応が必要(半角/全角・略称等)
後続Issueの進め方
- #922 データ設計書: 以下の設計を文書化する
RadioOnairSongへのartistNameフィールド追加- Prisma スキーマ変更とマイグレーション計画
- showId は
bonsoir(番組識別子)を想定
- #923 実装: スクレイピングスクリプト + GitHub Actions ワークフロー作成
- 初回は全過去回の遡及取得スクリプトも必要