ウェブ、ショウジン

Yahoo! pipesとMagpieRSSを使って複数Feedをまとめて表示

2011-12-11
Category
Web技術

異なるFeedフォーマット(RSS1.0だったりRSS2.0だったりAtomだったり)のブログ(Feed)をひとつにまとめて外部サイトで表示するメモ。

これまでは外部Feedをパースして表示するにはMagpieRSSだけ使っていたけれど、今回は複数の外部サイト(Feedを出力している)があって、しかもそれらが異なるFeedフォーマットということで、その差異を吸収しつつ、全てのFeedをまとめた上で時系列でソートする必要があったので、一番工数がかからずに済む方法を模索してみた。

まず、異なる複数のFeedをYahoo! Pipesというマッシュアップサービスを使ってまとめて(各Feedの取得件数、時系列でソートもここでやっちゃう)FeedのURLを取得し、これをMagpieRSSで読み込んだ上でその他に必要な処理(htmlタグや や全角スペースを取り除くとか、文字数を丸めるとか)をして出力する。

Yahoo! PipesはYahoo!(Japanではない)のIDが必要で、IDを取得した上で以下にログイン。

Pipes: Rewire the web

[adsenseSingleMid]

ログインしたらHomeから「Create Pipe」をクリックして自分のPipeを作る画面に移動。

スクリーンショット(2011-12-11 12.12.01)

左メニューにあるSourcesからFetch Feedをというモジュールを右側の作業エリアにドラッグ。このモジュールに取り込みたいFeedのURLを入力。このモジュールひとつで複数のFeedを取り込んでいけるけれど、最終的な出力で全Feedでの時系列でのソートがしたいので、今回は取得したいFeedごとにこのFetch Feedモジュールを用意する。(そうでないとひとつひとつのFeed単位でのソートになってしまう)

スクリーンショット(2011-12-11 12.32.29)

各FeedをFetch Feedモジュールに登録したら、取得する件数を設定するのに左メニューのOperatorsからTruncateモジュールを、これもFeedの数だけ作業エリアにドラッグ。このモジュールのTruncate feed afterという部分で取得したい件数を指定してFetch Feedモジュールとパイプでつなぐ。(Fetch Feedモジュールの下の青い丸とTruncateモジュールの上の青い丸をクリック&ドラッグでつなぐ)

スクリーンショット(2011-12-11 12.32.53)

ソートする前にFeed群をひとつにまとめたいので、左メニューのOperatorsからUnionモジュールを選んで作業エリアにドラッグ。各FeedのTruncateモジュールの下の青い丸をUnionモジュールの上部に五つある青い丸につなげる。(ということはUnionモジュールでまとめられるのは五つまでということかな?)

スクリーンショット(2011-12-11 12.33.22)

ひとつにまとめたFeed群を時系列でソートしたいので、左メニューのOperatorsからSortモジュールを選んで作業エリアにドラッグし、Unionモジュールの下にある青い丸とSortモジュールの上の青い丸を繋げる。

スクリーンショット(2011-12-11 12.34.24)

SortモジュールでSort byを「item.y:published」と入力し、降順にしたいのでdescendingを選択。(Sort byのところで「item:pubDate」を選ばないのは、RSS1.0とRSS2.0のこの部分の扱いの差異を吸収するため)

スクリーンショット(2011-12-11 12.34.39)

最後にPipe Outputモジュール(このモジュールはひとつでもモジュールを作業エリアにドラッグすると勝手に出てくる)とSortモジュールの青い丸をパイプでつなげたら画面右上のほうにあるSaveボタンをクリックして、作成したMy Pipeを名前を入力して保存。

サンプルとして実際のFeedを四つ読み込んで作成したPipeだと以下のようになった。

スクリーンショット(2011-12-11 12.35.52)

こうして複数のFeedをひとつにまとめたPipeのRSS Feed URLを取得したいので、ページ上部にあるBack to My Pipesという文字列をクリックして自分が作ったPipeの一覧ページへ移動する。

作成したPipeの名前をクリックすると読みこんでいるFeed群がListで表示されている。上部にあるGet as RSSという文字列をクリックすると、これらのまとめられたFeed URLにブラウザでアクセスできるので、このFeed URLをコピーしておく。(これが今回作成したPipeのFeed URLになる)

スクリーンショット(2011-12-11 12.42.54)

ここからはMagpieRSSでの作業。(MagpieRSSの使い方は以前書き残したMagpieRSSを使って外部サイトのfeedを読み込むを参照)

今回サンプルで読み込んでいるFeedのひとつ「facebook note」は、htmlタグやら半角スペース(&nbps;)やら全角スペースやら、いろいろ余計なものが入っているので(少なくとも今回は余計)これをphpのstrip_tagsやstr_replaceで除去する。

ちなみに、最初はjQueryで除いていたけれど、文字数を丸めるときにhtmlタグの途中で分断されたりして、その残りが表示されたりしたので、それはやめてphp側での処理にした。

タイトルと本文の出力文字数を適当な文字幅(phpのmb_strimwidthを使って)に丸める処理も追加して、ソースコードは以下のようになった。

<?php

// 必要モジュールの読み込み
require_once("./rss_fetch.inc");

// キャッシュは五分に設定
define("MAGPIE_CACHE_AGE", 60*5);

// キャッシュ保存ディレクトリ指定(事前にcache/ディレクトリを作成しておく)
define("MAGPIE_CACHE_DIR", "cache/");

// エンコーディングの設定
define("MAGPIE_OUTPUT_ENCODING", "UTF-8");

// 読み込むfeedのURL
$url = "http://pipes.yahoo.com/pipes/pipe.run?_id=465864fae71f1143bdf9e8f7d93eaeac&_render=rss";
$rss = fetch_rss($url);
$i=1;

// 表示する件数の上限
$max = 20;

foreach ($rss->items as $item) {

    // 記事本文へのリンクURLを取得
	$href = $item['link'];

	// 記事タイトルを取得
	$title = mb_convert_encoding($item['title'], "UTF-8", "auto");

	// 記事本文を取得
	$content = mb_convert_encoding($item['description'], "UTF-8", "auto");

	// 記事本文内のhtmlタグを除去
	$content = strip_tags($content);

	// &nbsp;と全角スペースの除去
	$content = str_replace("&nbsp;", "", $content);
	$content = str_replace(" ", "", $content);

	// タイトルと本文の文字数を丸める
	$title = mb_strimwidth($title, 0, 20, "…", "UTF-8");
	$content = mb_strimwidth($content, 0, 50, "…", "UTF-8");

	// 記事の投稿日時を取得して変数$dateに代入(RSS1.0だと['dc']['date'])
	$date = $item["pubdate"];

	// xmlで取得した投稿日時をdate関数を使って年月日形式に整形
	$date = date("Y年m月d日",strtotime($date));

	// 取得した各要素をhtmlで出力
	echo "<dl class=\"feed\">";
	echo "<dt><a href=\"$href\">$title</a><span>$date</span></dt>";
	echo "<dd>$content</dd>";
    echo "</dl>";

	// ループ処理ごとに$iの値に1を足す
	$i++;
	// $iの値が$maxの値を超えたらループ終了
	if($i > $max){break;}
}

?>

ついでに、各Feedごとにそれとわかる印をつけてみる。Feedの「link」項目で含まれるドメインで判別して、Feedの名称を出力して、色もつけてみる。

	// ドメインで判別して各Feedに印をつける
	if(strstr($item['link'], "web.showjin.me")){
		$blog = "<h2 class=\"web\">Web showjin / WordPress</h2>";
	}elseif(strstr($item['link'], "twitter.com")){
		$blog = "<h2 class=\"twitter\">showzine / Twitter</h2>";
	}elseif(strstr($item['link'], "facebook.com")){
		$blog = "<h2 class=\"fb\">facebook note</h2>";
	}elseif(strstr($item['link'], "showjin.jugem.cc")){
		$blog = "<h2 class=\"jugem\">showjin / jugem</h2>";
	};

最終的にはMagpieRSSを使ったソース部分は以下のようになった。

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja" lang="ja">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta http-equiv="content-language" content="ja" />
<meta http-equiv="Content-Style-Type" content="text/css" />
<meta http-equiv="Content-Script-Type" content="text/javascript" />
<meta name="description" content="" />
<meta name="keywords" content="" />
<title>Yahoo pipesとMagpieRSSを使って複数Feedをまとめて表示</title>
<link rel="stylesheet" href="css/reset.css" type="text/css" media="all" />
<link rel="stylesheet" href="css/fonts.css" type="text/css" media="all" />
<link rel="stylesheet" href="css/base2.css" type="text/css" media="all" />
</head>
<body>

<?php

// 必要モジュールの読み込み
require_once("./rss_fetch.inc");

// キャッシュは五分に設定
define("MAGPIE_CACHE_AGE", 60*5);

// キャッシュ保存ディレクトリ指定(事前にcache/ディレクトリを作成しておく)
define("MAGPIE_CACHE_DIR", "cache/");

// エンコーディングの設定
define("MAGPIE_OUTPUT_ENCODING", "UTF-8");

// 読み込むfeedのURL
$url = "http://pipes.yahoo.com/pipes/pipe.run?_id=465864fae71f1143bdf9e8f7d93eaeac&_render=rss";
$rss = fetch_rss($url);
$i=1;

// 表示する件数の上限
$max = 20;

foreach ($rss->items as $item) {

    // 記事本文へのリンクURLを取得
	$href = $item['link'];

	// 記事タイトルを取得
	$title = mb_convert_encoding($item['title'], "UTF-8", "auto");

	// 記事本文を取得
	$content = mb_convert_encoding($item['description'], "UTF-8", "auto");

	// 記事本文内のhtmlタグを除去
	$content = strip_tags($content);

	// &nbsp;と全角スペースの除去
	$content = str_replace("&nbsp;", "", $content);
	$content = str_replace(" ", "", $content);

	// タイトルと本文の文字数を丸める
	$title = mb_strimwidth($title, 0, 20, "…", "UTF-8");
	$content = mb_strimwidth($content, 0, 50, "…", "UTF-8");

	// 記事の投稿日時を取得して変数$dateに代入(RSS1.0だと['dc']['date'])
	$date = $item["pubdate"];

	// xmlで取得した投稿日時をdate関数を使って年月日形式に整形
	$date = date("Y年m月d日",strtotime($date));

	// ドメインで判別して各Feedに印をつける
	if(strstr($item['link'], "web.showjin.me")){
		$blog = "<h2 class=\"web\">Web showjin / WordPress</h2>";
	}elseif(strstr($item['link'], "twitter.com")){
		$blog = "<h2 class=\"twitter\">showzine / Twitter</h2>";
	}elseif(strstr($item['link'], "facebook.com")){
		$blog = "<h2 class=\"fb\">facebook note</h2>";
	}elseif(strstr($item['link'], "showjin.jugem.cc")){
		$blog = "<h2 class=\"jugem\">showjin / jugem</h2>";
	};


	// 取得した各要素をhtmlで出力
	echo "<h2>".$blog."</h2>";
	echo "<dl class=\"feed\">";
	echo "<dt><a href=\"$href\">$title</a><span>$date</span></dt>";
	echo "<dd>$content</dd>";
    echo "</dl>";

	// ループ処理ごとに$iの値に1を足す
	$i++;
	// $iの値が$maxの値を超えたらループ終了
	if($i > $max){break;}
}

?>

</body>
</html>

複数Feedをまとめたサンプル
http://web.showjin.me/demo/magpie/

外部サービスに依存していることとか、あんまりスマートではないけれど、現状の自分の能力で最短で今回の目的を果たそうとすると、これがベストだったと思う。また、触れたことのない「マッシュアップ」というものの一端に触れる機会となったのは決して悪くなかったかなと。とくにこのPipesっていうのは、アイデア次第でもっといろんなことができそう。

Categories

Tag Cloud

AdMob Android Apache centos CodeIgniter EC-CUBE facebookアプリ facebookページ feed Firefox Flash google googleanalytics htaccess iPad iPhone JavaScript lamp mobile nginx ogp pear php plugin rollover rss sendmail setting smarty ssh Titanium Mobile Titanium Studio tutorial ubuntu vim VirtualBox vmware vps Windows WordPress xampp youtube さくらインターネット アクセス解析 カスタム投稿