---
title: "調査レポート: 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 + 正規表現）を使用する。**

### 選定理由

1. JavaScript レンダリングが不要で実装コストが低い
2. 既存の HTML 解析パターン（各種スクリプト）を流用できる
3. 外部APIへの依存なく安定して収集可能
4. コスト無料

### 実装方針

```
collect-bonsoir-songs.ts
  → index.html を fetch で取得
  → 最新放送回の楽曲データを正規表現でパース
  → 未収集の過去回リンクを再帰的にたどる
  → RadioEpisode / RadioMember / RadioOnairSong に格納
  → GitHub Actions で毎週土曜午前に実行（放送翌朝）
```

### パース方針（暫定）

```typescript
// 楽曲行: M1「タイトル」（アーティスト）
const songPattern = /M(\d+)「(.+?)」（(.+?)）/g;

// 放送日: 2026年5月9日(土) → Date
const datePattern = /(\d{4})年(\d{1,2})月(\d{1,2})日/;
```

### 制約・リスク

- STVのHTML構造が変更された場合にパース処理の修正が必要
- 過去回の全アーカイブへのリンク体系が不明（一覧ページがなければ遡及取得が困難）
- アーティスト名の表記揺れへの対応が必要（半角/全角・略称等）

---

## 後続Issueの進め方

1. **#922 データ設計書**: 以下の設計を文書化する
   - `RadioOnairSong` への `artistName` フィールド追加
   - Prisma スキーマ変更とマイグレーション計画
   - showId は `bonsoir`（番組識別子）を想定
2. **#923 実装**: スクレイピングスクリプト + GitHub Actions ワークフロー作成
   - 初回は全過去回の遡及取得スクリプトも必要
