LoginSignup
6
9

More than 5 years have passed since last update.

RSSデータの取得とデータの蓄積サンプル

Last updated at Posted at 2015-05-30

昔(多分今もあるけど)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を実装しています。
それはまた次回に。

6
9
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
9