radiko番組表の必要部分を抽出して表示するプログラム(python)

Python

自作のFMラジオ放送の予約録音プログラムにおいて、現在放送されているラジオ番組名と出演者を表示する機能を追加してみました。

番組表は、radikoからxmlファイル形式でインターネット配信されており、xmlファイルから表示したいデータを抽出することで実装はできましたが、それなりの苦労は必要でした。

現在のradiko APIバージョンはV3となっており、ネット上にはradiko V2を抽出するサンプルプログラムしか見つけられなかったことから、ネットにある先輩方の情報を参考にして、xmlを勉強して作り直すことにしました。

現在はアナログ電波に関するプログラムを主体としており、xml解析を頻繁にするとは思えませんので、ファイルの入手から抽出方法までを備忘録として記事にしておくことにします。

radikoの番組表の仕様について

radikoエリア別の番組表の取得方法

radiko APIといってもxmlで配信されているだけですので、Webブラウザより以下サイトにアクセスすると、xml形式でソースファイルそのものが確認できます。

日付形式でも入手できましたが、ラジオ受信ソフトではあまり使い道がないため、説明は割愛します。

xmlファイルを見てみると、以下のような記述(抜粋)となっています。

<stations>
  <station id="ABC">
  <name>ABCラジオ</name>
    <progs>
      <date>20220309</date> 
       <prog id="9615977446" master_id="" ft="20220309220000" to="20220310003000" ftl="2200" tol="2430" dur="9000">
          <title>ABCミュージックパラダイス</title>
          <url>https://www.abc1008.com/abcmp/</url>
          <url_link></url_link>
          <failed_record>0</failed_record>
          <ts_in_ng>0</ts_in_ng>
          <ts_out_ng>0</ts_out_ng>
          <desc></desc>
          <info>ここは長いので省略</info>
          <pfm>北村真平、  リコ(ヤユヨ)   「ヤユヨアルバム発売記念!メンバー集合で徹底解説▼秋山黄色コメント▼北村真平アナ」   </pfm>
          <img>https://radiko.jp/res/program/DEFAULT_IMAGE/ABC/2fa275ec-9fec-4c75-aafb-d20ad9139b50.jpeg</img>
          <tag></tag>
          <genre><personality id="C004"><name>ミュージシャン</name></personality><program id="P005"><name>音楽</name></program></genre>
          <metas>
          <meta name="twitter" value="#ミューパラ" /><meta name="twitter" value="from:abcmp1008933" />
          </metas>
        </prog>
      
        <prog id="9615255954" master_id="" ft="20220310003000" to="20220310010000" ftl="2430" tol="2500" dur="1800">
          <title>ドローンネットpresents 小池徹平のSKY FIGHT</title>
          <url>https://www.abc1008.com/teppei_skyfight/</url>
          <url_link></url_link>
          <failed_record>0</failed_record>
          <ts_in_ng>0</ts_in_ng>
          <ts_out_ng>0</ts_out_ng>
          <desc></desc>
          <info>ここは長いので省略</info>
          <pfm>小池徹平、  永島聖羅</pfm>
          <img>https://radiko.jp/res/program/DEFAULT_IMAGE/ABC/38014fc0-c647-47f6-af14-af3d896e7600.jpeg</img>
          <tag></tag>
          <genre><personality id="C010"><name>タレント</name></personality><program id="P007"><name>トーク</name></program></genre>
          <metas>
          <meta name="twitter" value="#radiko" />
          </metas>
        </prog>
      
    </progs>

タグの解析とデータの抽出方法

radikoから入手したxmlファイルを解析し、タグから「番組タイトル」と「出演者」のみ抽出して、テキスト形式で番組情報を取り出すまでを実施してみます。

radikoのxmlタグ構造について

xmlファイルをよく眺めていると、radiko v3のタグ構造は以下のようになっていることが確認できます。

  • progs: プログラムタグ(1番組のくくり単位)
  • date: 番組の放送日付 形式:yyyymmdd
  • station id=ABC: 放送局ステーションの略称
  • name: 放送局の和名
  • prog ftl="0500" tol="0515":番組の開始と終了時刻
  • title: 番組タイトル(和名)
  • url: 番組のネットURL
  • pfm: 出演者
  • img: 番組のサムネイル画像データ

解析時の注意としては、progタグの子要素に開始と終了時刻が埋め込まれているところです。

この子要素を抜き出す方法が意外と面倒だと直感したので、最もコード記述量が少ない方法をとることにしました。

lxmlモジュールでタグ解析・抽出する

pythonでのxml解析と抽出は、lxml.etreeモジュールを使いました。

解析においては、特殊なことは何もしていませんので、他の解析モジュール(BeautifulSoup, ElementTreeなど)でも、宣言などのお作法が若干違うくらいだと思います。

解析と抽出の手順は以下に示します。タグの構造さえわかれば、上から順番に処理するだけですので、それほど大変ではありません。

何度となく試行錯誤を繰り返した結果、テキスト分を抽出するだけであれば、xpath()とget()のみで概ね抽出できました。

  1. rootは放送局の単位である「../station[id=(放送局コード)]」に設定する。
  2. 放送局の名前(name)と番組の日付はstation配下にある。
  3. 番組タグはprogタグ配下にあるため、for文でprogl内のタグ値を抽出する。
  4. progタグの子要素に開始と終了時刻がある。prog.get("子要素")にて時刻を抽出する。
  5. 抽出したデータはoutputという変数に順次追記し、最後のタグまで抽出出来たらreturnでまとめて返す。

インターネットにつながらない場合の処理を追加

製作しているラジオ受信ソフトはアナログ電波を復調するものですから、PCがインターネットに接続していない状態を考慮する必要があります。

インターネット未接続でxmlファイルが受信できない場合は、解析対象がなくエラーとなってしまいますので、requestモジュールを使って受信可否を最初に判断をすることにしました。

ネット接続していない場合は、戻り値に「番組表受信エラー」というテキスト文を設定することで、番組表に受信出来ない状態であることを表示し、プログラムの異常停止を回避できるように配慮しました。

作成したプログラム

予約録音ソフトのGUIプログラムから呼び出して使うことを想定し、radiko_v3()という独自関数にしています。

このpyファイルのdef()部分をimportすることで、radikoの仕様が変わっても、このpyファイルを修正するだけで対応できるようになります。

ソフトウェア品質を上げるには不必要に変えないということも重要な指標となるので、モジュール化できるのであればやっておいたほうが無難です。

#Copyright c 2021-2022 falconblog.org. All rights reserved.
import lxml.etree
import sys
import requests

def radiko_v3 (OPT):

# 番組表URL設定
#    RADIKO_URL = "http://radiko.jp/v3/program/today/JP13.xml"
    RADIKO_URL = "http://radiko.jp/v3/program/today/JP13.xml"
#    RADIKO_URL = "http://radiko.jp/v3/program/now/JP27.xml"

#URLアクセスチェック
    try:
        response = requests.get(RADIKO_URL)
        response.raise_for_status()
    except requests.exceptions.RequestException as e:
        output = '番組表受信エラー'
        return output
    else:
        pass

#URLの解析とタグ値抽出
    root = lxml.etree.parse(RADIKO_URL)
    progl = root.xpath('.//station[@id="' + str(OPT) +'"]')

    for progs in progl:
        name = progs.xpath('.//name')[0].text
        date = progs.xpath(".//date")[0].text # YYYYMMDD
        output = ("/".join(2024/04/26, date[4:6], date[6:8]]) + "  " + str(name))
        for prog in progs.xpath(".//prog"):
            title = prog.xpath(".//title")[0].text
            pfm = prog.xpath(".//pfm")[0].text
            stime = prog.get("ftl")  # HHMM
            etime = prog.get("tol")  # HHMM
            output += ("\n  " + stime[0:2] + ":"+stime[2:4] + " - " + etime[0:2] + ":" + etime[2:4]\
                + "  " + str(title) + '\n (出演)' + str(pfm))
    return output

# main
if __name__ == '__main__':
    args = sys.argv
    if len(args) == 2:
        pass
    else:
        print('Option Error!')
        quit()
    out = sys.argv[1]
    print(radiko_v3(str(out)))

サンプルプログラムの実行結果

pythonが動作する環境で以下設定のサンプルプログラムを実行してみます。

  • 場所の設定:東京(JP13.xml)
  • 番組表にする放送局:J-WAVE, id=FMJ
  • 番組表の日付:TODAY(本日)

結果は、以下の通り一日の番組が一覧で出るようになりました。参照するxmlファイルを"now"にすると現在の番組と次の番組の2つだけが入手できます。またプログラムに渡す引数を"FMT"にすると、「FM東京」の番組表が表示されます。

>python radiko_v3_fm_tokyo.py FMJ #引数J-WAVE=FMJ, FM東京=FMT,InterFM897=INT 
2022/03/13  J-WAVE
  05:00 - 06:00  MORNING VOYAGE
 (出演)nico
  06:00 - 09:00  MAKE MY DAY
 (出演)前田智子
  09:00 - 12:00  ACROSS THE SKY
 (出演)玄理
  12:00 - 13:00  TDK VOICES FROM NIHONMONO
 (出演)中田英寿 / 堀口ミイナ
  13:00 - 15:00  SAISON CARD TOKIO HOT 100(PART1)
 (出演)クリス・ペプラー
  15:00 - 17:00  SAISON CARD TOKIO HOT 100(PART2)
 (出演)クリス・ペプラー
  17:00 - 18:00  NX NIPPON EXPRESS SAUDE! SAUDADE…
 (出演)滝川クリステル
  18:00 - 19:00  UR LIFESTYLE COLLEGE
 (出演)吉岡里帆
  19:00 - 20:00  BRIDGESTONE DRIVE TO THE FUTURE
 (出演)ピストン西沢
  20:00 - 21:00  TUDOR TRAVELLING WITHOUT MOVING
 (出演)野村訓市
  21:00 - 22:00  Mercedes-Benz THE EXPERIENCE
 (出演)スガ シカオ
  22:00 - 23:00  J-WAVE SELECTION
 (出演) 
  23:00 - 24:00  TOPPAN INNOVATION WORLD ERA
 (出演)第1週 真鍋 大度、第2週 後藤 正文、第3週 のん、第4週 小橋 賢児
  24:00 - 25:00  GROWING REED
 (出演)岡田准一
  25:00 - 26:00  DIALOGUE RADIO-in the Dark-
 (出演)志村季世恵 / 板井麻衣子
  26:00 - 29:00  休止中
 (出演)

注意としては、radikoでネット配信しない放送局が結構存在することです。radiko経由で番組表が入手できない放送局は、個別にxml配信をしていないでしょうから、個別に放送局のホームページを見に行くしかありません。

以上、radiko v3 APIを使った番組表抽出プログラムの紹介でした。