首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 程式設計入門

Java RSS 解析實戰:基於 Rome 與 JDOM 解析新浪新聞訂閱源

     編輯:Java 程式設計入門

技術棧與依賴

本示例使用經典的 Rome 庫解析 RSS/Atom 訂閱源,依賴 JDOM 作為 XML 處理底層。

Maven 依賴坐標

<dependencies>
    <!-- Rome 1.x 版本 -->
    <dependency>
        <groupId>com.rometools</groupId>
        <artifactId>rome</artifactId>
        <version>1.18.1</version><!-- 請檢查最新版 -->
    </dependency>
    <!-- JDOM 2.x -->
    <dependency>
        <groupId>org.jdom</groupId>
        <artifactId>jdom2</artifactId>
        <version>2.0.6.1</version>
    </dependency>
</dependencies>

核心解析代碼

1. 簡單版:直接解析 URL

import com.rometools.rome.feed.synd.SyndEntry;
import com.rometools.rome.feed.synd.SyndFeed;
import com.rometools.rome.io.SyndFeedInput;
import com.rometools.rome.io.XmlReader;
import java.net.URL;
import java.util.List;

public class RssParserDemo {
    public static void main(String[] args) throws Exception {
        String feedUrl = "https://rss.sina.com.cn/news/marquee/ddt.xml";
        
        // 設置代理(如需要)
        System.setProperty("http.proxyHost", "mywebcache.com");
        System.setProperty("http.proxyPort", "8080");
        
        // 解析訂閱源
        SyndFeedInput input = new SyndFeedInput();
        SyndFeed feed = input.build(new XmlReader(new URL(feedUrl)));
        
        // 輸出頻道信息
        System.out.println("頻道標題: " + feed.getTitle());
        System.out.println("頻道鏈接: " + feed.getLink());
        System.out.println("頻道描述: " + feed.getDescription());
        System.out.println("發布語言: " + feed.getLanguage());
        System.out.println("最後更新: " + feed.getPublishedDate());
        System.out.println("文章數量: " + feed.getEntries().size());
        
        // 遍歷文章
        List entries = feed.getEntries();
        for (int i = 0; i < entries.size(); i++) {
            SyndEntry entry = entries.get(i);
            System.out.println("\n--- 第 " + (i+1) + " 條 ---");
            System.out.println("標題: " + entry.getTitle());
            System.out.println("鏈接: " + entry.getLink());
            System.out.println("發布時間: " + entry.getPublishedDate());
            System.out.println("作者: " + entry.getAuthor());
            System.out.println("摘要: " + entry.getDescription().getValue());
            
            // 獲取分類/標籤
            entry.getCategories().forEach(cat -> 
                System.out.println("分類: " + cat.getName()));
        }
    }
}

2. 進階版:自定義 HTTP 客戶端與錯誤處理

import com.rometools.rome.feed.synd.SyndFeed;
import com.rometools.rome.io.FeedException;
import com.rometools.rome.io.SyndFeedInput;
import com.rometools.rome.io.XmlReader;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import java.io.InputStream;
import java.time.Duration;
import java.util.concurrent.TimeUnit;

public class AdvancedRssParser {
    private static final OkHttpClient HTTP_CLIENT = new OkHttpClient.Builder()
            .connectTimeout(10, TimeUnit.SECONDS)
            .readTimeout(30, TimeUnit.SECONDS)
            .followRedirects(true)
            .build();
    
    public static SyndFeed parseFeed(String urlString) throws Exception {
        Request request = new Request.Builder()
                .url(urlString)
                .header("User-Agent", "Mozilla/5.0 (compatible; RSSReader/1.0)")
                .build();
        
        try (Response response = HTTP_CLIENT.newCall(request).execute()) {
            if (!response.isSuccessful()) {
                throw new RuntimeException("HTTP " + response.code() + ": " + response.message());
            }
            
            String contentType = response.header("Content-Type", "");
            if (!contentType.contains("xml") && !contentType.contains("rss") && !contentType.contains("atom")) {
                System.err.println("警告: Content-Type 可能非訂閱源格式: " + contentType);
            }
            
            try (InputStream is = response.body().byteStream()) {
                // XmlReader 自動檢測編碼
                return new SyndFeedInput().build(new XmlReader(is));
            }
        } catch (FeedException e) {
            throw new RuntimeException("訂閱源格式解析失敗: " + e.getMessage(), e);
        }
    }
    
    public static void main(String[] args) {
        try {
            SyndFeed feed = parseFeed("https://rss.sina.com.cn/news/marquee/ddt.xml");
            System.out.println("解析成功: " + feed.getTitle() + " (" + feed.getEntries().size() + " 條文章)");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

JSP 頁面展示示例(傳統 Web 應用)

<%@ page import="com.rometools.rome.feed.synd.*, com.rometools.rome.io.*, java.net.*, java.util.*" %>
<%@ page contentType="text/html;charset=UTF-8" %>
<html>
<head><title>新浪新聞 RSS 閱讀器</title></head>
<body>
<h1><%= feed.getTitle() %></h1>
<p>更新時間: <%= feed.getPublishedDate() %></p>

<table border="1" cellpadding="5" width="100%">
    <tr><th>序號</th><th>標題</th><th>發布時間</th><th>摘要</th></tr>
    <%
        List<SyndEntry> entries = feed.getEntries();
        for (int i = 0; i < entries.size(); i++) {
            SyndEntry entry = entries.get(i);
    %>
    <tr>
        <td><%= i + 1 %></td>
        <td><a href="<%= entry.getLink() %>" target="_blank"><%= entry.getTitle() %></a></td>
        <td><%= entry.getPublishedDate() %></td>
        <td><%= entry.getDescription() != null ? entry.getDescription().getValue() : "" %></td>
    </tr>
    <% } %>
</table>
</body>
</html>

常見問題與最佳實踐

1. 編碼問題處理

Rome 的 XmlReader 會自動從 XML 聲明、HTTP 響應頭、BOM 標記檢測編碼。若仍有亂碼,可強制指定:

// 強制 UTF-8
XmlReader reader = new XmlReader(new URL(feedUrl), "UTF-8");

2. 緩存策略減輕源站壓力

// 簡單內存緩存示例
private static final Map FEED_CACHE = new ConcurrentHashMap<>();

public static SyndFeed getFeedWithCache(String url, long ttlMinutes) {
    CacheEntry cached = FEED_CACHE.get(url);
    if (cached != null && System.currentTimeMillis() - cached.timestamp < ttlMinutes * 60 * 1000) {
        return cached.feed;
    }
    
    SyndFeed feed = parseFeed(url);
    FEED_CACHE.put(url, new CacheEntry(feed, System.currentTimeMillis()));
    return feed;
}

static class CacheEntry {
    final SyndFeed feed;
    final long timestamp;
    CacheEntry(SyndFeed feed, long timestamp) {
        this.feed = feed; this.timestamp = timestamp;
    }
}

3. 異步並發抓取多源

ExecutorService executor = Executors.newFixedThreadPool(5);
List> futures = urls.stream()
    .map(url -> CompletableFuture.supplyAsync(() -> {
        try { return parseFeed(url); } 
        catch (Exception e) { throw new CompletionException(e); }
    }, executor))
    .collect(Collectors.toList());

// 等待所有完成
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();
futures.forEach(f -> System.out.println(f.join().getTitle()));

Rome 庫核心類結構速查

類/接口用途
SyndFeed統一的訂閱源模型(兼容 RSS 0.9x/1.0/2.0, Atom 0.3/1.0)
SyndEntry單篇文章/條目
SyndContent內容模塊(摘要、全文),含 type(text/html) 與 value
SyndCategory分類/標籤
SyndPerson作者/貢獻者信息
SyndFeedInput解析器入口
WireFeedInput底層特定格式解析器(不建議直接使用)

總結

Rome 庫提供了統一的高層 API 屏蔽了 RSS/Atom 格式差異,配合現代 HTTP 客戶端(OkHttp)與緩存策略,可構建健壯的訂閱源聚合應用。關鍵點:異常處理、編碼自動檢測、緩存降低源站壓力、並發抓取提升效率。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved