Now On Air

以前、@miyabi_s さんに、FM京都のオンエア曲を Twitter に自動投稿する仕組みは無いものかと聞かれて、「オンエア楽曲検索を、スクレイピングして RSS フィードを作ってやればいいんじゃね?」と答えたことがありました。
ちゃちゃっと PHP でサンプルプログラムを作って渡したんですが、そのプログラムを利用して FM-NIIGATAFM PORTZIP-FM のオンエア曲を提供する bot を作成したので、ご紹介。

今回、作成したのは以下の4つのアカウントです。

動作原理を簡単に説明すると

  1. 各FM局公式サイトの「オンエア楽曲検索」をスクレイピングしてRSSフィードを作成
  2. cron で定期的にRSSフィードを確認して、新しい情報があれば Twitter に投稿

となります。

自前のサーバで cron 実行せずに twitterfeed.com などの外部サービスを利用したい時、移行が簡単になるようにわざわざRSSフィードを作成しています。
さて、ではプログラムの簡単な説明。

スクレイピングしてRSSフィードを作成

スクレイピング後、RSSフィードを作成するプログラムの骨組みを提示します。

<?php
// ライブラリをインクルード
require( 'Snoopy.class.php' );		// Snoopy
require( 'simple_html_dom.php' );	// PHP Simple HTML DOM Parser

// 定数の設定
define( 'ONAIR_URL',  'http://example.com/OnAirList.asp' );
define( 'RSS_LINK',   'http://example.com/index.asp' );
define( 'SITE_TITLE', 'FM HogeHoge Now On Air' );
define( 'ENCODING',   'UTF-8' ):
define( 'LANGUAGE',   'ja' );

// 変数の初期化
$lastpost = 0;
$posts = array();

// 最新の楽曲放送状況を取得
$snoopy = new Snoopy;
$snoopy->read_timeout = 5;
$snoopy->timed_out = true;
$snoopy->fetch( ONAIR_URL );
$response  = $snoopy->results;
$http_code = $snoopy->response_code;
unset($snoopy);
if ( strpos($http_code, '200') === FALSE ? ) die();

// 取得した HTML の解析
$html_txt = mb_convert_encoding( $response, ENCODING, 'SJIS-WIN, SJIS, EUCJP-WIN, EUCJP, JIS' );
$dom = str_get_html($html_txt);
if ($dom !== FALSE) {
	$elements = (array) $dom->find('table tbody tr');
	$item_count = 0; 
	foreach ($elements as $element) {
		/* 楽曲のタイトル、アーティスト、放送時間などを解析 */
			:
			:
		/* サイトの HTML 構造により、異なるので割愛 */

		$post = array(
			  'title' => $title
			, 'permalink' => $url
			, 'postdate' => $postdate
			, 'description' => $description
			, 'tags' => $tags
			);
		if ( array_search( $post, $posts ) === FALSE )
			$posts[] = $post;
	}
	unset($element); unset($elements);
}
unset($dom);

// RSSフィールドを書き出す
header('Last-Modified: '.gmdate('D, d M Y H:i:s', $lastpost).' GMT');
header('Content-Type: text/xml; charset=' . ENCODING, true);
echo '<?xml version="1.0" encoding="' . ENCODING . '"?' .">\n";
?>
<rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" version="2.0">

<channel>
	<title><?php echo SITE_TITLE; ?></title>
	<link><?php echo RSS_LINK; ?></link>
	<description><?php echo SITE_TITLE; ?></description>
	<pubDate><?php echo date('D, d M Y H:i:s +0900', $lastpost); ?></pubDate>
	<language><?php echo LANGUAGE; ?></language>
<?php foreach ( $posts as $post ) { ?>
	<item>
		<title><?php echo $post&#91;'title'&#93;; ?></title>
		<link><?php echo $post&#91;'permalink'&#93;; ?></link>
		<pubDate><?php echo date('D, d M Y H:i:s +0900', $post&#91;'postdate'&#93;); ?></pubDate>
		<guid><?php echo $post&#91;'permalink'&#93;; ?></guid>
		<description><!&#91;CDATA&#91;<?php echo $post&#91;'description'&#93;; ?>&#93;&#93;></description>
<?php foreach ((array) $post&#91;'tags'&#93; as $tag) { ?>
		<category><!&#91;CDATA&#91;<?php echo $tag; ?>&#93;&#93;></category>
<?php } ?>
	</item>
<?php } ?>
</channel>
</rss>

ざっと、こんな所です。

まず、Snoopy (simulates a web browser) を使用して、公式サイトのオンエア状況を取得します。(17-25行目)

次に取得してきた HTML から PHP Simple HTML DOM Parser を使用して、目的の情報を取り出します。(27-51行目)
PHP Simple HTML DOM Parser は、目的の DOM 要素を割りと簡単に取得できるのでお気に入りです。

で、最後に RSS フィードを吐き出す。(53-79行目)

簡単ですね。
これで、最新オンエア曲を吐き出す RSS フィードが出来上がりました。

RSSフィードを確認して、新しい情報があれば Twitter に投稿

RSSフィードさえできてしまえば、twitterfeed.com などの外部サービスを利用して、Twitter に投稿すれば良いのですが、これを自前でやるプログラムも提示しておきます。

<?php
// ライブラリをインクルード
require( 'dacRssParse.php' );

// 定数の設定
define( 'RSS_FEED',    'http://example.com/fm-hoge-on-air.php' );

define( 'TWITTER_USR', 'twitter_user_id' );
define( 'TWITTER_PWD', 'password' );
define( 'TWITTER_URL', 'http://twitter.com/statuses/update.xml?' );

define( 'UPDATE_TIME', 'update_time_hoge.txt' );

// 前回の最終投稿日時をファイルから取得
if (file_exists(UPDATE_TIME)) {
	$fp = fopen(UPDATE_TIME, 'r');
	$lastdate = strtotime(fread($fp, filesize(UPDATE_TIME)));
	fclose($fp);
} else {
	$lastdate = time();
}

// 指定の RSS フィードを順次読み込み Twitter に投稿する
$rss = new CDaRssParse;
$rss->setDebug(TRUE);
$rss->setFetchType($rss->FETCH_FILE);
if( $rss->parse(RSS_FEED) ) {
	$channel = $rss->getChannel();
	$pubdate = strtotime(isset($channel['pubDate']) ? $channel['pubDate'] : '');
	if ($pubdate > $lastdate) {
		foreach (array_reverse($rss->getItems()) as $item) {
			// オンエア時間が前回投稿時間よりも新しかったら Twitter に投稿する
			$pubdate = strtotime(isset($item['pubDate']) ? $item['pubDate'] : '');
			if ($pubdate > $lastdate) {
				// Twitter に投稿する情報を組み立てる
				$title = (isset($item['title']) ? $item['title'] : '');
				$link  = (isset($item['link']) ? ' '.get_tiny_url($item['link']) : '');
				$post  = $title . ' (' . date('Y.n.j G:i', $pubdate) . ')';
				$lastdate = $pubdate;

				// Twitter に投稿
				$params = "status=". rawurlencode($post);
				$result = file_get_contents(
					TWITTER_URL . $params ,
					false ,
					stream_context_create(array(
						"http" => array(
							"method" => "POST" ,
							"header" => "Authorization: Basic ". base64_encode(TWITTER_USR . ":" . TWITTER_PWD)
						)
					)));
			}
		}
		$lastdate = $pubdate;
	}
}
unset($rss);

// 最終投稿日時をファイルに保存
if(time() < $lastdate) $lastdate = time();
$fp = fopen(UPDATE_TIME, 'w');
fwrite($fp, gmdate("M d Y H:i:s", $lastdate).' GMT');
fclose($fp);
?>

今回は RSS の解析に daRssParser v1.0.3 を使用させていただきました。
以下のリンク先で配布されています。
DA実験室 :: PHP+MySQLのスクリプト配布

まず、ファイルに保存しておいた前回の最終投稿日時を取得。(14-21行目)

次に daRssParser で、RSSフィードを取得して、オンエア時間が前回投稿時間よりも新しかったら Twitter に投稿します。(23-57行目)

最後に最終投稿日時をファイルに保存して終了です。(59-63行目)

Now On Air」への2件のフィードバック

  1. ピンバック: Twitter OAuth 対応の話 : dogmap.jp

  2. ピンバック: M's Life 2 » ZIP-FM Now On Air

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください