【Python】ラジコの番組を検索するスクリプト
はじめに
ラズパイでラジコをタイムフリーで聞きたいときに、放送日時なんて覚えてないよってなっていた。キーワード検索して日時を取得すればよくね?と思い今回スクリプトを書いた。もともと需要がないせいかgoogle先生に聞いても思ったものは見当たらなかった。
確かにシェルスクリプトで済むことをわざわざPythonでやる必要もないですよね。
下調べ
ブラウザでラジコにアクセスして動作を確認します。
適当に検索してみた
- キーワード: 井口裕香
- 日付: すべて
- 地域: 東京
- 状態: タイムフリー
以下の画像の状態で検索。
結果は以下。
検索結果は1件ですね。
動作
ブラウザのデベロッパーツールを眺めて必要そうなところだけピックアップしました。
URL
基本URLは次のものでGETメソッドで取得している。
http://radiko.jp/v3/api/program/search
?以降はクエリ。付加されていたのは以下。
- action_id: 0
- app_id: pc
- area_id: JP13
- cul_area_id: JP13
- end_day:
- filter: past
- key: 井口裕香
- page_idx: 0
- region_id:
- row_limit: 12
- start_day:
- uid: e3948e8de187bab420a2fb4487f35675
レスポンス
嬉しいことに返ってくるのはjson形式のテキスト。
{
"meta": {
"searched_url": "",
"area_id": [
""
],
"region_id": "",
"page_idx": ,
"row_limit": ,
"start_day": "",
"cur_area_id": ,
"station_id": [],
"kakuchou": [],
"filter": "",
"end_day": "",
"key": [
""
],
"suisengo": "",
"result_count":
},
"data": [
{
"status": "",
"info": "",
"start_time_s": "",
"ts_in_ng": ,
"description": "",
"img": "",
"end_time_s": "",
"start_time": "",
"title": "",
"station_id": "",
"performer": "",
"metas": [
{
"name": "",
"value": ""
},
{
"name": "",
"value": ""
},
{
"name": "",
"value": ""
}
],
"end_time": "",
"program_date": "",
"ts_out_ng": ,
"program_url": ""
}
]
}
Pythonで書いてみる
処理のながれは以下。
- クエリを準備
- 'http://radiko.jp/v3/api/program/search'にクエリをつけてGET
クエリを準備
先程も書いたがクエリは以下のものがあった。すべて必要なのか確認していないが、確認が面倒なため全部用意します。
- action_id: 0
- app_id: pc
- area_id: JP13
- cul_area_id: JP13
- end_day:
- filter: past
- key: 井口裕香
- page_idx: 0
- region_id:
- row_limit: 12
- start_day:
- uid: e3948e8de187bab420a2fb4487f35675
'action_id','app_id',region_id','row_limit'は特に手を加える必要はなさそう。'page_idx'は、検索結果が複数ページになる場合に使用されるんだろうが、今回は0で固定。'area_id','cul_area_id'は、その名の通り地域の指定。'start_day','end_day'は、使用するつもりはないので今回はそのままにする。'filter'は、状態。放送済みを検索の場合'past'、まだ放送されていない場合'future'だった。'key'は検索ワードですね。
問題なのは'uid'。
'uid'は、cookieで用意されている'rdk_uid'の値が使われているようだ。common.jsに以下のコードが書かれていた。
generateUid: function () {
var _exp = $.cookie("rdk_uid");
if (_exp == null || _exp == "") {
var rnd = Math.floor(Math.random() * 1000000000) + "" + (new Date()).getTime();
_exp = MD5_hexhash(rnd);
$.cookie('rdk_uid', _exp, {path: '/'});
pythonで再現すると以下の感じだと思う(関数にしておく)。
import datetime, random, hashlib def generate_uid(): ''' rdk_uid生成関数 ''' rnd = random.random() * 1000000000 ms = datetime.timedelta.total_seconds(datetime.datetime.now() - datetime.datetime(1970, 1, 1)) * 1000 return hashlib.md5(str(rnd + ms)).hexdigest()
'key'と'filter','area_id','cul_area_id'は引数で受け取るとする。
とりあえず
形だけですが、こんな感じでクエリを用意する。
params = {
'key': 検索ワード,
'filter': 'future'か'past',
'start_day': '',
'end_day': '',
'area_id': エリアID,
'region_id': '',
'cul_area_id': エリアID,
'page_idx': '0',
'uid': generate_uid(),
'row_limit': '12',
'app_id': 'pc',
'action_id': '0',
}
'http://radiko.jp/v3/api/program/search'にクエリをつけてGET
あとは'requests'ライブラリを使用すれば簡単ですね。クエリの付加はライブラリに任せる。
import requests response = requests.get('http://radiko.jp/v3/api/program/search', params=辞書型で用意したクエリ)
'response.content'でjson形式のテキストなのであとは煮るなり焼くなり。
まとめ
上記のものをまとめると大体こんな感じになった。
#! /usr/bin/env python
# coding: utf-8 # ライブラリのインポート import datetime import random import hashlib import requests import json import codecs def search(keyword='', t='past', area_id='JP13'): ''' 番組検索関数 ''' # クエリの準備 params = { 'key': keyword, 'filter': t, 'start_day': '', 'end_day': '', 'area_id': area_id, 'region_id': '', 'cul_area_id': area_id, 'page_idx': '0', 'uid': generate_uid(), 'row_limit': '12', 'app_id': 'pc', 'action_id': '0', } # GET response = requests.get('http://radiko.jp/v3/api/program/search', params=params) # ファイルに出力して確認する # output(response.content) # json形式のテキストを整形して返す return json.loads(response.content) def generate_uid(): ''' rdk_uid生成関数 ''' rnd = random.random() * 1000000000 ms = datetime.timedelta.total_seconds(datetime.datetime.now() - datetime.datetime(1970, 1, 1)) * 1000 return hashlib.md5(str(rnd + ms)).hexdigest() def output(out): ''' ファイルに出力する関数 jsonの確認用 ''' out = json.loads(out) print out with codecs.open('./result01.json', 'w', 'utf-8') as f: json.dump(out, f, ensure_ascii=False, indent=4)
おわりに
長々書いたけど、何かの参考になれば幸いです。