RSS 2.0 結構速覽
<rss version="2.0">
<channel>
<title>頻道標題</title>
<link>https://example.com</link>
<description>頻道描述</description>
<item>
<title>文章標題</title>
<link>https://example.com/post/1</link>
<description><![CDATA[文章摘要...]]></description>
<pubDate>Mon, 01 Jan 2024 12:00:00 +0800</pubDate>
<guid>https://example.com/post/1</guid>
<category>分類</category>
</item>
...
</channel>
</rss>
核心解析代碼
<?php
/**
* 獲取 RSS 項目列表
* @param string $feedUrl
* @param int $limit 最大條數
* @return array [['title','link','desc','date','guid'], ...]
*/
function fetchRssItems(string $feedUrl, int $limit = 20): array {
$ctx = stream_context_create([
'http' => [
'timeout' => 10,
'user_agent' => 'Mozilla/5.0 (compatible; RSSReader/1.0)',
],
'ssl' => ['verify_peer' => false, 'verify_peer_name' => false], // 兼容自簽證書
]);
$xml = @simplexml_load_file($feedUrl, 'SimpleXMLElement', LIBXML_NOCDATA, $ctx);
if (!$xml) {
error_log("RSS parse failed: $feedUrl");
return [];
}
$items = [];
foreach ($xml->channel->item as $item) {
$items[] = [
'title' => (string)$item->title,
'link' => (string)$item->link,
'description' => (string)$item->description,
'pubDate' => isset($item->pubDate) ? strtotime((string)$item->pubDate) : time(),
'guid' => (string)($item->guid ?? $item->link),
'category' => (string)($item->category ?? ''),
];
if (count($items) >= $limit) break;
}
return $items;
}
// 使用示例
$feeds = [
'https://rss.sina.com.cn/news/world/focus15.xml',
'https://feeds.bbci.co.uk/news/world/rss.xml',
];
foreach ($feeds as $feed) {
$articles = fetchRssItems($feed, 5);
echo "<h2>$feed</h2><ul>";
foreach ($articles as $a) {
echo "<li><a href='{$a['link']}' target='_blank'>{$a['title']}</a> ";
echo "<small>" . date('Y-m-d H:i', $a['pubDate']) . "</small></li>";
}
echo "</ul>";
}
關鍵參數解析
- `LIBXML_NOCDATA`:將 CDATA 內容直接作為文本節點讀取,避免 `SimpleXMLElement` 對象包裹。
- `stream_context_create`:設置超時、User-Agent、SSL 驗證策略,防止卡死或證書錯誤。
- `(string)$node`:強制轉換為字符串,而非對象。
進階:聚合多源並按時間排序
function aggregateFeeds(array $feedUrls, int $total = 30): array {
$all = [];
foreach ($feedUrls as $url) {
$all = array_merge($all, fetchRssItems($url, 20));
}
// 按發布時間倒序
usort($all, fn($a, $b) => $b['pubDate'] <=> $a['pubDate']);
return array_slice($all, 0, $total);
}
緩存策略(生產必備)
function fetchRssCached(string $url, int $ttl = 300): array {
$key = 'rss_' . md5($url);
$data = apcu_fetch($key); // 或 Redis/Memcached
if ($data !== false) return $data;
$data = fetchRssItems($url);
apcu_store($key, $data, $ttl);
return $data;
}
異常格式兼容
| 異常情況 | 處理方式 |
| Atom 1.0 (feed 標簽) | 檢測 `$xml->getName() === 'feed'`,解析 `entry` 而非 `item` |
| 命名空間 (dc:creator, media:content) | `$item->children('dc', true)->creator` |
| 編碼非 UTF-8 | `simplexml_load_file` 自動按 XML 聲明解碼,若亂碼用 `mb_convert_encoding` |
| 超大文件 (>10MB) | 改用 `XMLReader` 流式解析 |
法律與禮儀
- 遵守 `robots.txt` 及站點服務條款。
- 設置合理 User-Agent,標明爬蟲身份。
- 請求間隔 ≥ 30 分鐘,或使用條件請求(`If-Modified-Since` / `ETag`)。
- 僅聚合允許轉載/摘要的內容,保留原文鏈接與版權聲明。
總結
`simplexml_load_file()` + `LIBXML_NOCDATA` 是 PHP 解析 RSS/Atom 最輕量高效的組合。配合緩存、超時、異常兼容,即可構建穩健的內容聚合服務。
- 上一篇文章: PHP 實現帶倒計時的頁面自動跳轉
- 下一篇文章: PHP GD 圖片處理類:生成多規格縮略圖、水印、裁剪
Copyright ©
程式碼之家 All Rights Reserved