以前、@miyabi_s さんに、FM京都のオンエア曲を Twitter に自動投稿する仕組みは無いものかと聞かれて、「オンエア楽曲検索を、スクレイピングして RSS フィードを作ってやればいいんじゃね?」と答えたことがありました。
ちゃちゃっと PHP でサンプルプログラムを作って渡したんですが、そのプログラムを利用して FM-NIIGATA、FM PORT、ZIP-FM のオンエア曲を提供する bot を作成したので、ご紹介。
今回、作成したのは以下の4つのアカウントです。
動作原理を簡単に説明すると
- 各FM局公式サイトの「オンエア楽曲検索」をスクレイピングしてRSSフィードを作成
- 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['title']; ?></title> <link><?php echo $post['permalink']; ?></link> <pubDate><?php echo date('D, d M Y H:i:s +0900', $post['postdate']); ?></pubDate> <guid><?php echo $post['permalink']; ?></guid> <description><![CDATA[<?php echo $post['description']; ?>]]></description> <?php foreach ((array) $post['tags'] as $tag) { ?> <category><![CDATA[<?php echo $tag; ?>]]></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行目)
ピンバック: Twitter OAuth 対応の話 : dogmap.jp
ピンバック: M's Life 2 » ZIP-FM Now On Air