複数のRSSフィードを高速でまとめる方法

当ブログの記事に共感していただけたら、また読みに来ていただけると嬉しいです。読んでくれる方の数が多くなると、更新するヤル気に繋がります(^^)

  • このエントリーをはてなブックマークに追加
  • Evernoteに保存Evernoteに保存

DSC_2723

クライアントさんからの依頼で、数十個のブログのRSSフィードをまとめて、日にち順にソートして記事をリスト表示するプログラムコードを書きました。

当初はYahoo!Pipesを利用していたのですが、フィード数が多すぎたのか、急にエラーを吐くようになってしまいました。そこで、フィード取得のコアの部分も一から作り直しました。

スポンサーリンク

並列読み込みで高速化

数十個のRSSフィードを1から順に読み込んでいては、時間がかかりすぎてしまいます。こういうときは、PHPでは「cURL multi」を利用すると、複数のフィードを一気に並列で読み込むことが可能です。

フィードのURLリストを渡すとフィードの生データをすべて出力してくれる関数を見つけたので、ありがたくそのまま利用させて頂きました。関数の中身には深く触れず、ブラックボックス的に利用しています。

今回はhtmlリストで出力しました。jsonなどのデータ形式で出力したりすれば、色々な用途に使えます。

複数のRSSフィードを高速でまとめるPHPコード

<?php

//表示記事数
$hyojiNum = 30;

//フィード登録
$data['feedurl'][] = 'http://rss.dailynews.yahoo.co.jp/fc/rss.xml';
$data['feedurl'][] = 'http://netafull.net/index.rdf';
$data['feedurl'][] = 'http://www.wakatta-blog.com/feed';// ※最後に「/」は付けないでください
//$data['feedurl'][] = ''; いくらでも追加してください

$rssList = $data['feedurl'];

//キャッシュ準備
require_once('Cache/Lite.php');
$cacheDir = 'rsscache/';
$lifeTime = 60*60;
$automaticCleaningFactor = 100;
$options = array('cacheDir' => $cacheDir ,'caching' => true, 'lifeTime' => $lifeTime, 'automaticSerialization' => 'true','automaticCleaningFactor' => $automaticCleaningFactor);
$cacheData = new Cache_Lite($options);

$outdata =  $cacheData->get('rsscache');


if(!$outdata) {

    //同時呼び出し
    $rssdataRaw = multiRequest($rssList);

    for($n=0;$n<count($rssdataRaw);$n++){
        //URL設定
        $rssdata = simplexml_load_string($rssdataRaw[$n]);
   
        if($rssdata->channel->item) $rssdata = $rssdata->channel;

        if($rssdata->item){

            foreach($rssdata->item as $myEntry){
 
                $rssDate = $myEntry->pubDate;
                if(!$rssDate) $rssDate = $myEntry->children("http://purl.org/dc/elements/1.1/")->date;
                date_default_timezone_set('Asia/Tokyo');
                $myDateGNU = strtotime($rssDate);
                $myDate = date('Y/m/d',$myDateGNU);
                $myTitle = $myEntry->title; //タイトル取得
                $myLink = $myEntry->link; //リンクURL取得
 
                //出力内容(CSSOK)
                if(preg_match('/PR:/',$myTitle)) continue;
           
                $outdata[$myDateGNU] =  '<p style="margin:0px">' . $myDate . ' ';
                $outdata[$myDateGNU].=  '<a href="' . $myLink . '" target="_blank">' . $myTitle . '</a></p>';
           
            }
        }
    }

    //ソート
    krsort($outdata);
   
    $cacheData->save($outdata,'rsscache');
}

$nn = 0;
$html = '';

foreach($outdata as $outdata) {
   
    $nn++;
    $html.= $outdata;
   
     if($nn == $hyojiNum) break;
   
}

$html = '<html lang="ja" style="overflow-x:hidden;"><head><META http-equiv="Content-Type" content="text/html; charset=utf-8"></head><div style="width:600px;font-size:13px">'.$html.'</div></html>';

echo $html;


//同時呼び出し関数
function multiRequest($data, $options = array()) {
 
  // array of curl handles
  $curly = array();
  // data to be returned
  $result = array();
 
  // multi handle
  $mh = curl_multi_init();
 
  // loop through $data and create curl handles
  // then add them to the multi-handle
  foreach ($data as $id => $d) {
 
    $curly[$id] = curl_init();
 
    $url = (is_array($d) && !empty($d['url'])) ? $d['url'] : $d;
    curl_setopt($curly[$id], CURLOPT_URL,            $url);
    curl_setopt($curly[$id], CURLOPT_HEADER,         0);
    curl_setopt($curly[$id], CURLOPT_RETURNTRANSFER, 1);
 
    // post?
    if (is_array($d)) {
      if (!empty($d['post'])) {
        curl_setopt($curly[$id], CURLOPT_POST,       1);
        curl_setopt($curly[$id], CURLOPT_POSTFIELDS, $d['post']);
      }
    }
 
    // extra options?
    if (!empty($options)) {
      curl_setopt_array($curly[$id], $options);
    }
 
    curl_multi_add_handle($mh, $curly[$id]);
  }
 
  // execute the handles
  $running = null;
  do {
    curl_multi_exec($mh, $running);
  } while($running > 0);
 
  // get content and remove handles
  foreach($curly as $id => $c) {
    $result[$id] = curl_multi_getcontent($c);
    curl_multi_remove_handle($mh, $c);
  }
 
  // all done
  curl_multi_close($mh);
 
  return $result;
}

?>

上記コードのデモはこちら

もっと良い方法があれば、ぜひ教えてください!

※お行儀よくフィードを取得するため、キャッシュ(Cache/Lite.php)を入れてます。もしお使いのサーバーにインストールされていなかったら、Package Information: Cache_Liteからダウンロードして、同じ階層にCache/フォルダーをアップロードしてください。そして、キャッシュファイルを保存するrsscacheディレクトリを同階層に置いてください。

【参考】
複数APIの読み込みを高速化させる

今日のわかった

フィードをまとめてくれるサービスはどんどん閉鎖されています。マネタイズが難しく、サーバー負荷増に対応できないのだと思います。

自前のサーバー上でまとめてしまうのが一番確実かなと思います。

関連記事
スポンサーリンク

当ブログの記事に共感していただけたら、また読みに来ていただけると嬉しいです。読んでくれる方の数が多くなると、更新するヤル気に繋がります(^^)

  • このエントリーをはてなブックマークに追加
  • Evernoteに保存Evernoteに保存

フォローしていただけると、ブログ更新を見逃しません

push7 feedly
スポンサーリンク

コメント

  1. コンヤガヤマダ より:

    色んなサイト見てきましたが一番参考になり、エラーも出ずに出来ました。
    どうもありがとうございます。
    他のサイトはコードをコピーしたらエラーがあり、
    やはりデモページがあると動く安心感があります。

コンヤガヤマダ にコメントする コメントをキャンセル

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