昔(多分今もあるけど)mixiに「mixiニュース」というコンテンツありました。これは単にニュースを見れるだけではなく、そのニュースについてコメント的に日記を書くことができるコンテンツで、自分は一時期これにめっちゃハマってました。
ですがご存知の通り、足あと機能の廃止により「足あと」と言う名のアクセスカウンタ機能が消え失せ、結果大幅にモチベーションが低下してついに書かなくなりました。
とはいえ人間一度味をしめるとなかなか脱却できないもので、何かどうにかしてやれないかなあと考えたところ
「そうだニュースのRSSを解析して自前のデータベースに蓄積しとけばいいんだ」
「確かアレって元記事のURLもあるし見出し見て気に入ったニュースを見て書けばいいんだ」
「ついでにmixiみたく見出しやURLを『引用』(これ大事)とかにしとけば似た感じになるぞ」
という結論に至りこれを実装してみました。
実装に必要なもの
・レンタルサーバー
・php
・mysql
テーブル定義
テーブルその1、rssデータをを配信してるサイトを管理するテーブル
CREATE TABLE rssmaster (
id int(10) NOT NULL AUTO_INCREMENT ,
name varchar(255) DEFAULT NULL,
url varchar(255) DEFAULT NULL,
dispname varchar(255) DEFAULT NULL,
rdf varchar(255) DEFAULT NULL,
status int(1) DEFAULT 1,
version varchar(10) DEFAULT NULL,
created timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
updated timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
PRIMARY KEY (id)
) ENGINE=MyISAM AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
サンプルデータ。
INSERT INTO rssmaster (id, name, url, dispname, rdf, status, version, itemlimit, created, modified) VALUES (1,'マイナビニュース - その先を伝える総合情報サイト','http://news.mynavi.jp/','MYCOMジャーナル','http://rss.rssad.jp/rss/mycom/index',1,'1.0',0,'2013-09-04 12:20:17','2013-09-04 12:20:17');
INSERT INTO rssmaster (id, name, url, dispname, rdf, status, version, itemlimit, created, modified) VALUES (2,'マイナビウーマン | エキサイトニュース','http://www.excite.co.jp/News/source/Escala/','マイナビウーマン最新配信記事 | エキサイトニュース','http://www.excite.co.jp/News/rss/source/?source=Escala',1,'1.0',0,'0000-00-00 00:00:00','0000-00-00 00:00:00');
INSERT INTO rssmaster (id, name, url, dispname, rdf, status, version, itemlimit, created, modified) VALUES (3,'メンズサイゾー | エキサイトニュース','http://www.excite.co.jp/News/source/Menscyzo/','メンズサイゾー最新配信記事 | エキサイトニュース','http://www.excite.co.jp/News/rss/source/?source=Menscyzo',1,'1.0',0,'0000-00-00 00:00:00','0000-00-00 00:00:00');
INSERT INTO rssmaster (id, name, url, dispname, rdf, status, version, itemlimit, created, modified) VALUES (4,'サイゾーウーマン | エキサイトニュース','http://www.excite.co.jp/News/source/Cyzowoman/','サイゾーウーマン最新配信記事 | エキサイトニュース','http://www.excite.co.jp/News/rss/source/?source=Cyzowoman',1,'1.0',0,'0000-00-00 00:00:00','0000-00-00 00:00:00');
INSERT INTO rssmaster (id, name, url, dispname, rdf, status, version, itemlimit, created, modified) VALUES (5,'朝日新聞デジタル:朝日新聞社のニュースサイト','http://www.asahi.com/','朝日新聞デジタル速報ニュース','http://rss.asahi.com/rss/asahi/newsheadlines.rdf',0,'1.0',0,'2013-09-14 22:07:09','2013-09-14 22:07:09');
INSERT INTO rssmaster (id, name, url, dispname, rdf, status, version, itemlimit, created, modified) VALUES (6,'新着ニュース : YOMIURI ONLINE(読売新聞)','http://www.yomiuri.co.jp/latestnews/','YOMIURI ONLINE 新着ニュース','http://rss.yomiuri.co.jp/rss/yol/latestnews30',1,'2.0',0,'2013-09-14 22:09:01','2013-09-14 22:09:01');
テーブルその2、記事データを管理するテーブル
CREATE TABLE rssdata (
itemkey varchar(32) NOT NULL,
id int(10) NOT NULL,
sitetitle text,
sitedescription text,
sitelink text,
itemtitle text,
itemdescription_body text,
itemdescription_plane text,
itemdescription_image text,
itemdescription_title text,
itemdescription_comment text,
to varchar(255) DEFAULT NULL,
itemlink text,
status int(1) DEFAULT '1',
version varchar(10) DEFAULT NULL,
created timestamp NOT NULL DEFAULT '0000-00-00 00:00:00' ,
modified timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
PRIMARY KEY (itemkey),
KEY id (id)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
RSSデータをとってくるプログラム(parserdf.php)
<?php
//include("feedcreator.class.php");
mb_internal_encoding("utf-8"); // 内部エンコード指定@文字化け対策
$newslimit = 1; // サイトごとの件数はrssmasterにもたせた
$newscount = 0;
$dbHost="127.0.0.1";
$dbUser="mysql";
$dbPass="password";
$db_select = mysql_connect($dbHost, $dbUser, $dbPass);
mysql_set_charset("utf8",$db_select); // DBエンコード指定@文字化け対策
$db_selected = mysql_select_db('rssbbs', $db_select);
$timestamp = date("YmdHis");
System("mysqldump -u root rssbbs rssdata --password=password > rssdata.$timestamp.txt");
mysql_query("DELETE FROM rssdata WHERE ( status = 0 AND ( itemdescription_comment IS NULL OR itemdescription_comment = '' ))
OR modified < date_add(current_timestamp, interval -7 day) ");
$ret = mysql_query("SELECT * FROM rssmaster WHERE status = 1 ORDER BY id");
while ($array = mysql_fetch_array($ret))
{
$id = $array['id'];
$newslimit = $array['itemlimit'];
$version = $array['version'];
//$result = simplexml_load_file($array['rdf']);
// 2013.06.29 description中のCDATAをテキストとして取得
$result = simplexml_load_file($array['rdf'], 'SimpleXMLElement', LIBXML_NOCDATA);
// 2013.08.27 配列型に変換
$result = json_decode(json_encode($result), true);
$sitetitle = NULL;
$sitedescription = NULL;
$sitelink = NULL;
// sitetitle
if (array_key_exists('title', $result['channel']))
{
$sitetitle = $result['channel']['title'];
}
else
{
$sitetitle = $array['dispname'];
}
// sitedescription
if (array_key_exists('description', $result['channel']) && is_string($result['channel']['description']))
{
$sitedescription = $result['channel']['description'];
}
else
{
$sitedescription = $array['name'];
}
// sitelink
if (array_key_exists('link', $result['channel']))
{
$sitelink = urlcheck((string)$result['channel']['link'], $array['url']);
}
else
{
$sitelink = $array['url'];
}
$isitems=false;
$items=array();
// RSS Version1.0
if ($version === '1.0')
{
if (array_key_exists('item', $result))
{
$isitems=true;
$items=$result['item'];
}
}
// RSS Version2.0
elseif($version === '2.0')
{
if (array_key_exists('item', $result['channel']))
{
$isitems=true;
$items=$result['channel']['item'];
}
}
if ($isitems){
$newscount = 0;
foreach($items as $item)
{
// newslimit=0は全件
if ($newslimit != 0){
if ($newscount >= $newslimit) break;
$newscount++;
}
$itemtitle = NULL;
$itemlink = NULL;
$itemkey = NULL;
$itemdescription_source = NULL;
$itemdescription_image = NULL;
$itemdescription_plane = NULL;
$itemdescription_body = NULL;
$itemtitle = (array_key_exists('title', $item)) ? $item['title'] : "";
if (! is_string($itemtitle))
{
continue;
}
if (substr($itemtitle,0,2) === 'PR' || substr($itemtitle,0,2) == 'AD' || substr($itemtitle,1,2) == 'PR')
{
continue;
}
$itemlink = (array_key_exists('link', $item)) ? $item['link'] : "";
$itemkey = md5($itemlink); // 記事単位のkey生成
$itemdescription_source = (array_key_exists('description', $item)) ? $item['description'] : "";
if (is_string($itemdescription_source)){
$itemdescription_image = getimage($itemdescription_source);
$itemdescription_plane = strip_tags($itemdescription_source);
$itemdescription_plane = str_replace(array("\r\n","\r","\n"), '', $itemdescription_plane);
$itemdescription_body = str_replace("'","\"",$itemdescription_source);
$itemdescription_body = str_replace("<p>", "", $itemdescription_body);
$itemdescription_body = str_replace("</p>", "", $itemdescription_body);
$itemdescription_body = str_replace(array("\r\n","\r","\n"), '', $itemdescription_body);
}
$check_sql = "SELECT itemkey FROM rssdata WHERE itemkey = '$itemkey'";
$check_ret = mysql_query($check_sql);
$check_array = mysql_fetch_array($check_ret);
if(empty($check_array) || $check_array[0]['itemkey'] === '')
{
$replace_sql = "INSERT INTO rssdata
(
id,
sitetitle,
sitedescription,
sitelink,
itemkey,
itemtitle,
itemdescription_body,
itemdescription_plane,
itemdescription_image,
itemlink,
status,
version
)
VALUES
(
$id,
'$sitetitle',
'$sitedescription',
'$sitelink',
'$itemkey',
'$itemtitle',
'$itemdescription_body',
'$itemdescription_plane',
'$itemdescription_image',
'$itemlink',
0,
'$version'
)";
$replace_sql = str_replace(array("\r\n","\r","\n", "\t" ), '', $replace_sql);
mysql_query($replace_sql);
logging(array(
'id' => $id,
'sitetitle' => $sitetitle,
'sitedescription' => $sitedescription,
'sitelink' => $sitelink,
'itemkey' => $itemkey,
'itemtitle' => $itemtitle,
'itemdescription_body' => $itemdescription_body,
'itemdescription_plane' => $itemdescription_plane,
'itemdescription_image' => $itemdescription_image,
'itemlink' => $itemlink,
'version' => $version));
}
}
}
}
mysql_close($db_select);
// ---------------------------------------------------------------
// functions
// ---------------------------------------------------------------
// url1の形式チェック・存在チェックをする。両方trueならurl1を、falseがあればurl2を返す
function urlcheck($url1,$url2)
{
$returl = $url1;
// url形式チェック
if (preg_match('/^(https?|ftp)(:\/\/[-_.!~*\'()a-zA-Z0-9;\/?:\@&=+\$,%#]+)$/', $url1))
{
// URL存在チェック
if($fp = @fopen($url1, 'r'))
{
fclose($fp);
}
else
{
$returl = $url2;
}
}
else
{
$returl = $url2;
}
return $returl;
}
// imgタグ抜き出し
function getimage($str)
{
if (!is_string($str)) return;
if (preg_match('/(\<img).*(gif|jpg|jpeg|png)(.*?>)/', $str, $match))
{
return str_replace("'","\"",$match[0]);
}
else
{
return "";
}
}
function logging($array)
{
$log = NULL;
$log.= date("Y/m/d H:i:s")." : ";
$Ymd = date("Ymd");
foreach($array as $key => $value)
{
if (is_numeric($key))
{
continue;
}
$log.= "$key=$value,";
}
$log = substr($log,0,-1);
$log.= "\n";
$logfile = str_replace("php","log",$_SERVER['PHP_SELF']) ;
error_log($log,3,'/var/log/'.$logfile);
}
?>
使い方
mysqlにテーブル作ってphpのソースにmysqlのアクセス設定してparserdf.phpをcli起動すれば動くはずです。
これだけだと見る方法がないので実運用にはcakePHPにてWebUIを実装しています。
それはまた次回に。