使用PHP解析RSS/Atom订阅的最佳方法

140

我目前正在使用Magpie RSS,但当RSS或Atom源不规范时,它有时会崩溃。是否有其他用于解析PHP中RSS和Atom源的选项?


1
这个请求有一个问题,大多数Feed阅读器都使用php的核心XML阅读器,如果XML格式不符合XML标准要求,它将会崩溃。你可以查看那些不使用XML阅读器而使用文本阅读器的阅读器,但服务器负载将会显著增加。我知道这个问题已经得到了解答,我只是想让人们意识到使用XML feed阅读器的缺点。 - Barkermn01
1
永远不要尝试解析无效的XML。责备数据源。 - Lothar
10个回答

172
我一直使用PHP内置的SimpleXML函数来解析XML文档。它是少数几个具有直观结构的通用解析器之一,这使得为特定的东西(比如RSS订阅)构建一个有意义的类变得非常容易。此外,它还能检测XML的警告和错误,如果发现任何问题,你可以简单地通过类似HTML Tidy的工具来清理源代码,然后再次尝试。
考虑一下这个非常简单的使用SimpleXML的类:
class BlogPost
{
    var $date;
    var $ts;
    var $link;

    var $title;
    var $text;
}

class BlogFeed
{
    var $posts = array();

    function __construct($file_or_url)
    {
        $file_or_url = $this->resolveFile($file_or_url);
        if (!($x = simplexml_load_file($file_or_url)))
            return;

        foreach ($x->channel->item as $item)
        {
            $post = new BlogPost();
            $post->date  = (string) $item->pubDate;
            $post->ts    = strtotime($item->pubDate);
            $post->link  = (string) $item->link;
            $post->title = (string) $item->title;
            $post->text  = (string) $item->description;

            // Create summary as a shortened body and remove images, 
            // extraneous line breaks, etc.
            $post->summary = $this->summarizeText($post->text);

            $this->posts[] = $post;
        }
    }

    private function resolveFile($file_or_url) {
        if (!preg_match('|^https?:|', $file_or_url))
            $feed_uri = $_SERVER['DOCUMENT_ROOT'] .'/shared/xml/'. $file_or_url;
        else
            $feed_uri = $file_or_url;

        return $feed_uri;
    }

    private function summarizeText($summary) {
        $summary = strip_tags($summary);

        // Truncate summary line to 100 characters
        $max_len = 100;
        if (strlen($summary) > $max_len)
            $summary = substr($summary, 0, $max_len) . '...';

        return $summary;
    }
}

2
你有一个没有开始标签的结束标签。 ;) - Talvi Watia
133
我原本有一个代码,但由于它上面没有空行,被我的 SO 代码格式化程序给吃掉了。另外,你的句子开头没有大写字母哦 ;) - Brian Cline
4
除此之外,请将“$feed_uri = $feed_or_url;”更改为“$feed_uri = $file_or_url;”……除此之外,感谢您提供这段代码!它很好用! - Tim
5
请注意,尽管这个解决方案很好,但它只能解析当前形式下的RSS源。由于其不同的架构,Atom源将无法被解析。 - András Szepesházi
9
请注意,eregi_replace现已被弃用,并被preg_replace所取代,eregi也被preg_match所取代。相关文档可以在此处找到:http://php.net/manual/en/function.preg-replace.php 和 http://php.net/manual/en/function.preg-match.php。 - ITS Alaska
显示剩余3条评论

48

用4行代码,我将一个rss导入到一个数组中。

$feed = implode(file('http://yourdomains.com/feed.rss'));
$xml = simplexml_load_string($feed);
$json = json_encode($xml);
$array = json_decode($json,TRUE);

对于更为复杂的解决方案

$feed = new DOMDocument();
 $feed->load('file.rss');
 $json = array();
 $json['title'] = $feed->getElementsByTagName('channel')->item(0)->getElementsByTagName('title')->item(0)->firstChild->nodeValue;
 $json['description'] = $feed->getElementsByTagName('channel')->item(0)->getElementsByTagName('description')->item(0)->firstChild->nodeValue;
 $json['link'] = $feed->getElementsByTagName('channel')->item(0)->getElementsByTagName('link')->item(0)->firstChild->nodeValue;
 $items = $feed->getElementsByTagName('channel')->item(0)->getElementsByTagName('item');

 $json['item'] = array();
 $i = 0;

 foreach($items as $key => $item) {
 $title = $item->getElementsByTagName('title')->item(0)->firstChild->nodeValue;
 $description = $item->getElementsByTagName('description')->item(0)->firstChild->nodeValue;
 $pubDate = $item->getElementsByTagName('pubDate')->item(0)->firstChild->nodeValue;
 $guid = $item->getElementsByTagName('guid')->item(0)->firstChild->nodeValue;

 $json['item'][$key]['title'] = $title;
 $json['item'][$key]['description'] = $description;
 $json['item'][$key]['pubdate'] = $pubDate;
 $json['item'][$key]['guid'] = $guid; 
 }

echo json_encode($json);

2
我刚试了一下,它没有返回一个数组。 - samayo
你能给我你正在使用的 RSS 订阅源吗? - PJunior
2
如果你在想,看起来他正在使用Tumblr的RSS源。任何tumblrsite.com/rss都会给你相同的输出。 - andrewk
5
使用了这4行代码,做得很好 :) 但是我重写了第一行代码:$feed = file_get_contents('http://yourdomains.com/feed.rss'); 可能比使用文件和implode函数更加高效。 - Guidouil
3
$feed = json_decode(json_encode(simplexml_load_file('http://news.google.com/?output=rss')), true); - Will Bowman
显示剩余2条评论

29

5
Zend Feed是一个用于读取和生成Web Feeds(如RSS和Atom)的PHP库,它由Zend Framework开发。该库提供了一组易于使用的API来创建、解析和输出Web Feeds。您可以使用Zend Feed在您的应用程序中轻松地集成Web Feeds的读取和创建功能。 - artur
196
我不喜欢这样的“答案”,没有任何评论就给出链接。看起来像是你在谷歌搜索并链接了一些热门结果。特别是因为提问者有一些 RSS 经验,需要一个更好的解析器。 - duality_
3
如果有人需要一点建议,Last RSS 是上述三个中最容易使用的。只需一个文件进行 "require”,并且可以在 5 行内获取 RSS 并得到相当好的数组输出。 - Raptor
picoFeed https://github.com/fguillot/picoFeed - gadelat
我已经使用了其中两个,LastRss似乎没有提供完全功能的帮助程序,而SimplePie则有点过于复杂。我想尝试其他一些库,但是对这些库的评论更适合让人们理解,而不仅仅是链接。 - noob

27

我想介绍一个简单的脚本来解析RSS:

$i = 0; // counter
$url = "http://www.banki.ru/xml/news.rss"; // url to parse
$rss = simplexml_load_file($url); // XML parser

// RSS items loop

print '<h2><img style="vertical-align: middle;" src="'.$rss->channel->image->url.'" /> '.$rss->channel->title.'</h2>'; // channel title + img with src

foreach($rss->channel->item as $item) {
if ($i < 10) { // parse only 10 items
    print '<a href="'.$item->link.'">'.$item->title.'</a><br />';
}

$i++;
}

清晰简单的解决方案!运行良好。 - John T
与使用 $xml = simplexml_load_string($feed) 不同,这种方法非常简单,而且在打印数据时也很方便... - Srinivas08

13
如果提供的内容不是格式良好的XML,你应该拒绝它,没有例外。你有权称呼提供内容的人为傻瓜
否则,你会为混乱铺平道路,这可能导致HTML出现在其中。

3
+1,您不应尝试处理任何未格式化的XML。我们曾经有过这样的经历,相信我,那是一场大灾难 :( - Helen Neely
36
然而,程序员不能选择商业伙伴,必须解析他们所接收到的内容。 - Edmond Meinfelder
2
如果你正在构建一个通用的RSS/Atom订阅阅读器,那该怎么办?如果任何格式不正确的XML文件都可以“破坏”你的HTML,那么谁是这个笨蛋?;)在接收数据时要宽容。 - yPhil

6

HTML Tidy库能够修复一些格式不正确的XML文件。在将其传递给解析器之前,通过该库运行您的订阅源可能会有所帮助。


1

就个人而言,我使用BNC高级Feed解析器 - 我喜欢模板系统非常易于使用


1

1

我使用SimplePie来解析Google Reader的RSS源,它运行良好且功能齐全。

当然,我还没有测试过它对于非格式良好的RSS/Atom源的处理能力,但我假设Google的源都是符合标准的! :)


-2

无法说使用gzinflate和base64_decode是“很好的”,通常出于安全考虑而禁用。 - Will Bowman
这是一个用于营销目的的失效链接。 - Sagive

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接