X
pm studio world wide news pj club
pm studio world wide news pj club
news, tech, music, film, sports, cg, translation, photo uploader
  • 2015-12-21
  • PJ Club
  • Creating Original RSS News Feed with PHP / PHPでオリジナルRSS Newsfeed作成
  • PJ Club3回目はRSSの情報を取得する方法です。RSSのニュースフィード取得には、Google Feed APIが有名ですが、残念ながら、11月にサービスが終了してしまいました。
    替わりにYahooのYQLを利用する方法もあります。しかし、良く考えたらRSSはXMLですから、PHPでアクセスすると割と簡単に情報を取得できます。PHPであれば、クロスドメインの問題もありません。(JavaScriptで他のWebサイトへアクセスしようとすると、クロスドメインの関係で制限がある)
    だだし、PHPはクライアント側のスクリプトではありませんから、JavaScriptのようにローカルで確認できないのが、面倒くさいと言う点はあります。
    PHPでRSSの情報を取得するには、simplexmlを利用します。このsimplexmlは、XMLの各要素へ簡単にアクセス出来る機能で、PHP5以上であれば、標準で装備されています。
    simplexmlの詳細は、こちらhttp://www.w3schools.com/php/php_ref_simplexml.aspに記述されています。
    まず、標準的なRSSのXMLの内容を見てみましょう。

    <rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" version="2.0">
         <channel>
                  <item>
                      <title>記事のタイトル</title>
                      <link>WebサイトへのリンクURL</link>
                      <pubDate>日付</pubDate>
                      <description>記事の詳細</description>
                  </item>
         </channel>
    </rss>

    では、XMLの要素から、データを取得してみます。XMLファイルの読み込みは、下記のようにします。

    <?php
         //XMLファイルのURL
         $xml = "XMLファイルのURL";
         //XMLファイルの読み込み
         $xmlData = simplexml_load_file($xml,'SimpleXMLElement',LIBXML_NOCDATA);
         //XMLファイルの名前空間の取得
         $namespaces = $xmlData->getNamespaces(true);
    ?>

    XMLファイルの読み込みでは、$xmlData = simplexml_load_file($xml);とするWebサイトが多いのですが、これだと画像ファイルのURLを取得する時に、不具合があったりします。
    そこで、細かくエレメント取得の設定をするsimplexml_load_file($xml,'SimpleXMLElement',LIBXML_NOCDATA);にします。
    $xmlData->getNamespaces(true);は、名前空間と言われ、コロンを含む要素の取得時に使います。
    次に、各要素を取得します。一般的なXMLでは<channel>要素の下に<item>要素があります。この<item>要素がブロックとなって、記事の数だけ記述されています。
    <item>要素の取得は下記の通りです。

    $xmlData->channel->item

    これで、XMLファイル内の<item>要素をすべて取得できます。続いて、<item>内の各要素を取得しますが、存在する<item>数を取得する必要があります。PHPにはforeachと言う繰り返しのファンクションがありますので、それを使って<item>数を知ります。
    記述はこんな感じです。

    foreach ($xmlData->channel->item as $data){
         各要素取得のスクリプト
    }

    各要素取得のスクリプトですが日付からいってみましょう。日付は、たいてい<pubDate>Wed, 16 Dec 2015 05:55:00 -0500</pubDate>のように秒数まで記述されています。そこで、date("Y-m-j G:i", strtotime());と言う関数で、年、月、日、時、分だけにします。

    $date_raw=$data->pubDate;
    $date=date("Y-m-j G:i:, strtotime($date_raw));

    続いてタイトルです。

    $title=$data->title;

    リンク先です。

    $link=$data->link;

    記事の詳細です。

    $description=$data->description;

    まとめると、

    <?php
         $xml = "XMLファイルのURL";
         $xmlData = simplexml_load_file($xml,'SimpleXMLElement',LIBXML_NOCDATA);
         $namespaces = $xmlData->getNamespaces(true);

         foreach ($xmlData->channel->item as $data){
                  $date_raw=$data->pubDate;
                  $date=date("Y-m-j G:i", strtotime($date_raw));
                  $title=$data->title;
                  $link=$data->link;
                  $description=$data->description;
         }
    ?>

    となります。ここまでは、取得しただけなので、HTML Tagで出力します。
    HTML Tagを生成するスクリプトです。

    $xmlDATA .="
                      <div>$date</div>
                      <div><a href='$link'>$title</a></div>
                      <div>$description</div>
                      ";

    .=は、「=」以降を追加していきます。つまり取得した<item>数だけ、HTML tagを生成しています。
    まとめると

    <?php
         $xml = "XMLファイルのURL";
         $xmlData = simplexml_load_file($xml,'SimpleXMLElement',LIBXML_NOCDATA);
         $namespaces = $xmlData->getNamespaces(true);

         foreach ($xmlData->channel->item as $data){
                  $date_raw=$data->pubDate;
                  $date=date("Y-m-j G:i", strtotime($date_raw));
                  $title=$data->title;
                  $link=$data->link;
                  $description=$data->description;

                  $xmlDATA .="
                                      <div>$date</div>
                                      <div><a href='$link'>$title</a></div>
                                      <div>$description</div>
                                      ";
         }
         //HTML出力
         echo $xmlDATA;
    ?>

    このスクリプトに、ファイル名 (例. xml_data.php)を付け、サーバーにアップすると、HTMLとして出力されます。
    Directlyricsと言うアメリカの音楽サイトのRSSでデモ作ってみました。RSSのURLは、「http://www.directlyrics.com/news.xml」です。

    サンプルはここをクリック
  • simplexml_load_file()は、とてもシンプルにXMLデータの要素を取得できます。
    では、$namespacesって何?ということで、RSSのフォーマットでは次のようなケースがあります。

    <rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" version="2.0">
         <channel>
                  <item>
                      <title>記事のタイトル
                      <link>WebサイトへのリンクURL
                      <pubDate>日付
                      <description>記事の詳細
                      <media:thumbnail url="画像のURL"/>記事に関する写真、画像
                  </item>
         </channel>
    </rss>

    これは、<media:thumbnail url="画像のURL"/>に画像データのURLを記述しているケースです。この画像URLを取得する時に、$namespacesを使用します。
    <media:thumbnail url="画像のURL"/>のようのコロン「:」のついた要素を名前空間のついた要素と呼びます。
    この場合、下記のように記述すると画像のURLを取得出来ます。

    $imgURL=$data->children($namespaces['media'])->thumbnail->attributes()->url;

    まとめると、

    <?php
         $xml = "XMLファイルのURL";
         $xmlData = simplexml_load_file($xml,'SimpleXMLElement',LIBXML_NOCDATA);
         $namespaces = $xmlData->getNamespaces(true);

         foreach ($xmlData->channel->item as $data){
                  $date_raw=$data->pubDate;
                  $date=date("Y-m-j G:i:s", strtotime($date_raw));
                  $title=$data->title;
                  $link=$data->link;
                  $description=$data->description;
                  $imgURL=$data->children($namespaces['media'])->thumbnail->attributes()->url;

                  $xmlDATA .="
                                      <div>$date</div>
                                      <div><a href='$link'>$title</a></div>
                                      <div>$description</div>
                                      <div><img src='$imgURL'></div>
                                      ";
         }
         //HTML出力
         echo $xmlDATA;
    ?>

    先程の音楽サイトDirectlyricsの画像付きデモです。

    サンプルはここをクリック
  • これで、文字データだけでなく、画像も取得出来ました。さて、画像の取得はこれだけではない場合があります。
    名前空間を使わず、<description>内にHTMLと同様のimg tagを記述しているケースです。
    この場合、記事の詳細を取得した際に、画像、動画が一緒に表示されてしまいます。
    RSSリーダーfeedlyのように、詳細データと画像データをちゃんとレイアウトして表示したい場合等、ちょっと困りますね。
    そこで、画像データだけを記事の詳細から抽出し、記事の詳細は文字データだけにします。
    画像のimg tagを抽出するには正規表現を使用します。img tag抽出の正規表現で下記の例が多く見かけられます。

    "/<img.*>/i"、または、"/<img.*src\s*=\s*[\"|\'](.*?)[\"|\'].*>/i"

    この正規表現は確かにimg tagを取得出来ますが、img tagが複数存在する場合、最初のimg tagから次のimg tagまでに記述された文字も一緒に抽出してしまいます。
    そこで、下記のようにすると複数のimg tagが存在していても、img tagだけを取得出来ます。

    '/<img[^>]*>/i'、または、'/<img[^>]*src\s?=\s?[\"\']([^\"\']+)[\"\'][^>]*>/i'

    文章の中には、いくつimg tagがあるか分かりませんから、すべてのimg tagを探し出すpreg_match_all("検索対象", "検索文章", "検索結果")という関数を使用します。

    preg_match_all('/<img[^>]*>/i', $description, $result);

    このpreg_match_all("検索対象", "検索文章", "検索結果")は、検索対象が見つかると自動的に「検索結果」へ配列として保存してくれます。
    今回、配列の中のimg tagを1個表示したいので、下記のようにして「検索結果」から1個目を取得します。

    $imgURL=$result[0][0];

    続いて、記事の詳細内の画像はいりませんから、文字データだけにします。方法は、str_replace("置き換え前の文字", "置き換え後の文字", "置き換える対象文章")関数を使って、見つけ出したimg tagをすべて空白に置き換えます。

    foreach ($result[0] as $key){
         $description=str_replace($key,'', $description);
    }

    まとめると、

    <?php
         $xml = "XMLファイルのURL";
         $xmlData = simplexml_load_file($xml,'SimpleXMLElement',LIBXML_NOCDATA);
         $namespaces = $xmlData->getNamespaces(true);

         foreach ($xmlData->channel->item as $data){
                  $date_raw=$data->pubDate;
                  $date=date("Y-m-j G:i:s", strtotime($date_raw));
                  $title=$data->title;
                  $link=$data->link;
                  $description=$data->description;
                  //画像取得
                  preg_match_all('/<img[^>]*>/i', $description, $result);
                  $imgURL=$result[0][0];
                  //画像削除
                  foreach ($result[0] as $key){
                          $description=str_replace($key,'', $description);
                  }

                  $xmlDATA .="
                                      <div>$date</div>
                                      <div><a href='$link'>$title</a></div>
                                      <div>$description</div>
                                      <div>$imgURL</div>
                                      ";
         }
         //HTML出力
         echo $xmlDATA;
    ?>

    となります。
    サンプルでは、アメリカのTechサイトEngadgetのRSSを取得してみました。RSSのURLは、「http://www.engadget.com/rss.xml」です。

    サンプルはここをクリック

    RSSはいくつかのパターンに分けられます。取得したいRSSがどのパターンに属するのかは、XMLの要素を調べ、パターンを判断する方法もあります。
    XMLの要素を調べるには、getName()関数を使います。下記のようにすると、各要素名が$itemNameに配列として格納されます。

    $itemName=$xmlData->children()->children()->getName();

    多分、取得したい複数のRSSが予め分かっているのであれば、この要素名を調べるより、各RSSのURL、パターンをデータベースに登録しておいて、呼び出す方が早いと思います。
    代表的なパターンです。

    Aパターン
    <channel>
         <item>
                  <title>記事のタイトル</title>
                  <link>WebサイトへのリンクURL</link>
                  <pubDate>日付</pubDate>
                  <description>記事の詳細</description>
         <item>
    </channel>

    Bパターン
    <channel>
         <item>
                  <title>記事のタイトル</title>
                  <link>WebサイトへのリンクURL</link>
                  <pubDate>日付</pubDate>
                  <description>記事の詳細</description>
                  <media:thumbnail url="画像のURL"/>記事に関する写真、画像
         </item>
    </channel>

    Cパターン
    <channel>
         <item>
                  <title>記事のタイトル</title>
                  <link>WebサイトへのリンクURL</link>
                  <pubDate>日付</pubDate>
                  <description>記事の詳細</description>
                  <enclosure url="画像のURL"/>記事に関する写真、画像
         </item>
    </channel>

    Dパターン
    <channel>
         <item>
                  <title>記事のタイトル</title>
                  <link>WebサイトへのリンクURL</link>
                  <pubDate>日付</pubDate>
                  <description>記事の詳細</description>
                  <content:encoded>記事に関する写真、画像</content:encoded>
         </item>
    </channel>

    Eパターン
    <channel>
         <item>
                  <title>記事のタイトル</title>
                  <link>WebサイトへのリンクURL</link>
                  <pubDate>日付</pubDate>
                  <description>記事の詳細</description>
                  <media:content url="画像のURL">記事に関する写真、画像</media:content>
         </item>
    </channel>

    Fパターン
    <channel>
         <item>
                  <title>記事のタイトル</title>
                  <link>WebサイトへのリンクURL</link>
                  <pubDate>日付</pubDate>
                  <description>記事の詳細</description>
                  <image>記事に関する写真、画像</image>
         </item>
    </channel>

    Gパターン
    <entry>
         <title>記事のタイトル</title>
         <link>WebサイトへのリンクURL</link>
         <published>日付</published>
         <content>記事の詳細</
    </entry>

    ただし、すべてのWebサイトがRSSを用意しているかと言うと、そうでもありません。では、どうやって最新情報を取得するか。HTMLからニュースフィードを作成する方法もあります。
    次回は、XMLからではなくHTMLからニュースフィードを作ってみます。
  • source : pm studio world wide news
Recent Post
Latest News
Billboard Hot 100
Top 10
  • No.1
    In My Feelings
    Drake
  • No.2
    Girls Like You
    Maroon 5 & Cardi B
  • No.3
    I Like It
    Cardi B, Bad Bunny & J Balvin
  • No.4
    Better Now
    Post Malone
  • No.5
    Lucid Dreams
    Juice WRLD
  • No.6
    I Love It
    Kanye West & Lil Pump
  • No.7
    Sicko Mode
    Travis Scott
  • No.8
    Fefe
    6ix9ine, Nicki Minaj & Murda Beatz
  • No.9
    Love Lies
    Khalid & Normani
  • No.10
    Taste
    Tyga & Offset
BBC Radio 1 Singles 40
Top 10
  • No.1
    Promises
    Calvin Harris & Sam Smith
  • No.2
    Eastside
    Benny Blanco, Khalid & Halsey
  • No.3
    I Love It
    Kanye West & Lil Pump
  • No.4
    Body
    Loud Luxury
  • No.5
    Happier
    Marshmello & Bastille
  • No.6
    Taste
    Tyga & Offset
  • No.7
    Girls Like You
    Maroon 5 & Cardi B
  • No.8
    Electricity
    Silk City & Dua Lipa
  • No.9
    Fall
    Eminem
  • No.10
    All I Am
    Jess Glynne
  • Editor: Toshio Maeoka / pm studio
    pm studio world wide news © 2014-2018 . All Rights Reserved
^
to TOP