HTMLとJavaScriptで番組表取得システムを作る方法について解説!

◆ Live配信スケジュール ◆
サイオステクノロジーでは、Microsoft MVPの武井による「わかりみの深いシリーズ」など、定期的なLive配信を行っています。
⇒ 詳細スケジュールはこちらから
⇒ 見逃してしまった方はYoutubeチャンネルをご覧ください
【5/21開催】Azure OpenAI ServiceによるRAG実装ガイドを公開しました
生成AIを活用したユースケースで最も一番熱いと言われているRAGの実装ガイドを公開しました。そのガイドの紹介をおこなうイベントです!!
https://tech-lab.connpass.com/event/315703/

インターンシップ学生の高倉です。ここでは、HTMLとJavaScriptで番組表を取得し、表示するための方法について順を追って解説しようと思います。今回は、NHK番組表APIを使用し、フォームから開始時間と終了時間のデータを受け取っているという前提で解説します。

NHK番組表APIを使うための準備

NHK番組表APIからデータを取得するためには、ユーザ登録する必要があります。

1.まず、NHK番組表APIのホームページ(https://api-portal.nhk.or.jp/)にアクセスし、右上の新規登録をクリックします。

2.必要な情報を入力し、アカウントを作成します。

3.入力したメールアドレスにメールが届くので、認証します。

4.番組表APIの新規アプリ登録ページで必要事項を記入しAPIキーの発行を申請します。

5.ホームページの「登録済みアプリはこちら」のボタンをクリックすると、登録したアプリの情報が表示されます。それをクリックすると、APIの取得に必要なキーが表示されます。

URLからデータを取得する方法

ほかのサイトでも、フォームを入力した後に

・・・.html?○○=××&△△=××

といった表記を見たことはあるでしょうか?今回はこの機能を使っていきます。

    function getparam(name){
        url=window.location.href;
        name = name.replace(/[\[\]]/g, "\\$&");
        var regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)");
        var results = regex.exec(url);
        if (!results) return null;
        if (!results[2]) return '';
        return decodeURIComponent(results[2].replace(/\+/g, " "));

    }

 

HTMLで表の素体を作る方法

Tableを用いて、表を作ります。見出しは表の最初の行で設定します。

プログラム




<table id="table" class="table table-striped">
    
<caption>Powered by NHK番組表API</caption>

    
<tr>
        <!--表の見出し-->
        
<th>放送局</th>

        
<th>番組名</th>

        
<th>放送開始時間</th>

        
<th>放送終了時間</th>

        
<th>ジャンル</th>


    </tr>

    
<tr>
        <!--APIから取得したデータを埋め込む。
        serviceは放送局
        nameは番組のメインタイトル
        timeは放送開始時間
        endは放送終了時間
        genreはジャンルの番号に対応している。
        -->
        
<td>
<div id="service"> </div>
</td>

        
<td>
<div id="name"> </div>
</td>

        
<td>
<div id="time"> </div>
</td>

        
<td>
<div id="end"> </div>
</td>

        
<td>
<div id="genre"> </div>
</td>

    </tr>

    
</table>



最初のtr要素では、表の見出しを表示できるようにしています。実際の表では、上に書いた要素から左に並んでいきます。
二つ目のtr要素では、情報を表示するための箇所を確保しています。

serviceは放送局名
nameは番組名
timeは放送開始時間
endは放送終了時間
genreはジャンル名に対応しています。

APIからデータを取得する方法

NHK番組表APIでは、YYYY-MM-DDの形式で月日を指定します。月や日が一桁の時は頭に0をつけないと正常に取得できないため、その場合は条件分岐で頭に0をつける処理をします。
JavaScriptでは1個しか変数を返すことができないので、リストの形で返します。

プログラム

function makeURLpart(iyear,imonth,iday){
    var year
    var month
    var day
    year=String(iyear)
    if(imonth<10){
        month="0"+String(imonth)
    }else{
        month=String(imonth)
    }

    if(iday<10){
        day="0"+String(iday)
    }else{
        day=String(iday)
    }
    return [year,month,day]
}
このプログラムでは、APIから情報を取得するためにURLの一部分を作成しています。
URLは文字列で指定するため、ここで文字列に変換します。
YYYY-MM-DD形式で日時を指定するため、月や日が一桁となる場合には、前に0をつけることで対応します。最後に作成したyear,month,dayを返します。
URLに必要なパラメータを作成できたら、次にURLを取得します。
プログラム
function getURL(ch,year,month,day){
    request=new XMLHttpRequest()
    var url="https://api.nhk.or.jp/v2/pg/list/130/"+ch+"/"+year+"-"+month+"-"+day+".json?key=キーを入力"
    request.open("GET",url,true)
    request.responseType="json"
    return request

}

第一引数のchでは、取得するチャンネルを指定しています。対応表は以下の通りです
引数

チャンネル名

g1NHK総合
e1NHKEテレ
e4NHKワンセグ
s1NHKBS
s3BSプレミアム

ほかの引数のyear,month,dayは、取得したい日にちを入力します。

最後に、取得したデータを返します。

入力された時間が日をまたぐ場合の対応方法

日にちを進める関数を利用して、1日分進めた後、もう一度APIからデータを取得します。うるう年や30日31日の月の日数の違いも考慮します。

プログラムは以下の通りです。

function progressDay(y,m,d){
    var mday={
        1:31,
        2:28,
        3:31,
        4:30,
        5:31,
        6:30,
        7:31,
        8:31,
        9:30,
        10:31,
        11:30,
        12:31

    }
    if(y%4==0){
        mday[2]=29
    }else{
        mday[2]=28
    }

    if(d==mday[m]){
        if(m==12){
            d=1
            m=1
            y+=1
        }else{
            m+=1
            d=1
        }
    }else{
        d+=1
    }

    return [y,m,d]

}

 

表に適した情報を反映させる方法

最後に、取得したデータから放送局・番組名・番組開始時間・番組終了時間・ジャンルを取り出します。

プログラム

function writeTable(req,ch){
    var data=req;
    console.log(data);
    var len
    //要求されたチャンネルに応じて取り出す要素を変更する。
    if(ch=="g1"){
        len=Object.keys(data.list.g1).length;
    }else if(ch=="e1"){
        len=Object.keys(data.list.e1).length;
    }else if(ch=="e4"){
        len=Object.keys(data.list.e4).length;
    }else if(ch=="s1"){
        len=Object.keys(data.list.s1).length;
    }else if(ch=="s3"){
        len=Object.keys(data.list.s3).length;
    }else{
        console.log("無効なチャンネルが指定されています");
    }

    
    console.log(ch)
    var service
    var name
    var time
    var end
    var genre

    for(let i=0;i<len;i+=1){
        if(ch=="g1"){
            service=data.list.g1[i].service.name;
            name=data.list.g1[i].title;
            time=data.list.g1[i].start_time;
            end=data.list.g1[i].end_time;
            genre=data.list.g1[i].genres[0];
        }else if(ch=="e1"){
            service=data.list.e1[i].service.name;
            name=data.list.e1[i].title;
            time=data.list.e1[i].start_time;
            end=data.list.e1[i].end_time;
            genre=data.list.e1[i].genres[0];
        }else if(ch=="e4"){
            service=data.list.e4[i].service.name;
            name=data.list.e4[i].title;
            time=data.list.e4[i].start_time;
            end=data.list.e4[i].end_time;
            genre=data.list.e4[i].genres[0];
        }else if(ch=="s1"){
            service=data.list.s1[i].service.name;
            name=data.list.s1[i].title;
            time=data.list.s1[i].start_time;
            end=data.list.s1[i].end_time;
            genre=data.list.s1[i].genres[0];
        }else if(ch=="s3"){
            service=data.list.s3[i].service.name;
            name=data.list.s3[i].title;
            time=data.list.s3[i].start_time;
            end=data.list.s3[i].end_time;
            genre=data.list.s3[i].genres[0];
        }
        
        if(time>starttime && end<endtime){
            console.log("時間の範囲内")
            console.log("放送局:"+service);
            console.log("番組名:"+name);
            console.log("開始時間:"+time);
            console.log("終了時間:"+end);
            console.log("ジャンル:"+genre);
            //表を拡張
            var add=table.insertRow(-1);
            var cell1=add.insertCell(-1);
            var cell2=add.insertCell(-1);
            var cell3=add.insertCell(-1);
            var cell4=add.insertCell(-1);
            var cell5=add.insertCell(-1);
            //時間などの要素を取り出す
            time=String(time);
            end=String(end);
            genre=String(genre);
            timeymd=time.substr(0,10);
            timehms=time.substr(11,5);
            eymd=end.substr(0,10);
            ehmd=end.substr(11,5);
            //ジャンルを大ジャンルと小ジャンルに分ける
            var big_genre=genre.substr(0,2);
            var small_genre=genre.substr(2,);
            //大ジャンルと小ジャンルをもとに、表示を完成させる
            if(big_genre=="00"){
                genre="ニュース/報道"
                if(small_genre=="00"){
                    genre+="(定時・総合)"
                }else if(small_genre=="01"){
                    genre+="(天気)"
                }else if(small_genre=="02"){
                    genre+="(特集・ドキュメント)"
                }else if(small_genre=="03"){
                    genre+="(政治・国会)"
                }else if(small_genre=="04"){
                    genre+="(経済・市況)"
                }else if(small_genre=="05"){
                    genre+="(海外・国際)"
                }else if(small_genre=="06"){
                    genre+="(解説)"
                }else if(small_genre=="07"){
                    genre+="(討論・会談)"
                }else if(small_genre=="08"){
                    genre+="(報道特番)"
                }else if(small_genre=="09"){
                    genre+="(ローカル・地域)"
                }else if(small_genre=="10"){
                    genre+="(交通)"
                }else{
                    genre+="(その他)"
                }
              ...ジャンルを記入していく

            }else{
                genre="その他"
            }
            
            cell1.innerHTML=service
            cell2.innerHTML=name
            cell3.innerHTML=timeymd+"\n"+timehms;
            cell4.innerHTML=eymd+"\n"+ehmd;
            cell5.innerHTML=genre

        }else{
            console.log("時間の範囲外")
        }
        
        
    }
}

取得した時間の範囲内に収まる(最初から最後まで見れる)番組だけを表示します。
今回使用したNHKの番組表APIはジャンルの上二桁は大ジャンル、下二桁は小ジャンルに分かれている
ため、ジャンルの数字を二桁ずつに分割して、大ジャンルと小ジャンルに分け、それに応じたジャンル名を表示するようにしています。

プログラム全体の流れ

ここまではすべてFunction機能を使用してきました。最後に、Function同士をつなげて、実行できるようにします。ここでは、NHK総合の番組表を取得する場合を示しています。

プログラム

nymd=[iyear,imonth,iday]
for(j=0;j<2;j+=1){
    var uymd
    uymd=makeURLpart(nymd[0],nymd[1],nymd[2])
    req=getURL("g1",uymd[0],uymd[1],uymd[2])

    req.addEventListener("load",function(){
        writeTable(this.response,"g1")
        
    })

    
    req.send()
    nymd=progressDay(nymd[0],nymd[1],nymd[2])
    
}
まず日にちを取得し、その日にちからURLを作ります。その後、URLを取得し、取得出来たら表に書くという流れになっています。最後にsendを挟むことで表に反映し、次の日にちに設定します。
それを2回繰り返す流れです。
二重にFor文を設定すると、addEventListenerの仕様で正常に動作しないため、実際には5つのチャンネルを別々に動作させています。
アバター画像
About サイオステクノロジーの中の人 1 Article
サイオステクノロジーで働く中の人です。
ご覧いただきありがとうございます! この投稿はお役に立ちましたか?

役に立った 役に立たなかった

0人がこの投稿は役に立ったと言っています。


ご覧いただきありがとうございます。
ブログの最新情報はSNSでも発信しております。
ぜひTwitterのフォロー&Facebookページにいいねをお願い致します!



>> 雑誌等の執筆依頼を受付しております。
   ご希望の方はお気軽にお問い合わせください!

Be the first to comment

Leave a Reply

Your email address will not be published.


*


質問はこちら 閉じる