多站點RSS新聞正文抓取,導入discuz論壇,自動發帖的實現(一)

公司研發部不能上外網,但是公司又希望研發的同事能關注下新聞,瞭解科技熱點,跟上時代潮流。所以搭建了一個discuz論壇, 但內容匱乏。幸運的是搭這臺論壇的服務器可以上網的(在兩個網絡裏面)。所以想着要我做一個爬蟲工具,通過rss把新聞內容,抓取過來放到公司論壇。

  現在已經實現了,同時抓取多個網站上面的數據(IT之家,虎嗅網等等),只有文字沒有圖片。當然圖片抓取,我也會嘗試做出來。目前的效果還不錯。網絡上關於RSS讀取的文字特別多,但是關於rss中鏈接指向正文的抓取比較少,正好這幾天做這樣一個項目,現在把設計思想和關鍵代碼貼出來分享一下。   源碼已經整理上傳,在文章最底部有鏈接。



一、先簡單介紹下RSS

1:  什麼是RSS
 RSS(really simple syndication) :網頁內容聚合器。RSS的格式是XML。必須符合XML 1.0規範。
 RSS的作用:訂閱BLOG,訂閱新聞
2  RSS的歷史版本:
 http://blogs.law.harvard.edu/tech/rssVersionHistory
 RSS的版本有很多個,0.90、0.91、0.92、0.93、0.94、1.0 和 2.0。與RSS相對的還有ATOM。
 國內主要是RSS2.0,國外主要用ATOM0.3.
 由於RSS出現2派,導致混亂場面。其中RSS2.0規範由哈佛大學定義並鎖定。
 地址:http://blogs.law.harvard.edu/tech/rss

 3:  解析jar:Rome: http://wiki.java.net/bin/view/Javawsxml/Rome
 Rome是 java.net 上的一個開源項目,現在的版本是1.0。爲什麼叫Rome呢,按它的介紹上的說法,有個“條條大路通羅馬”的意思,有些RSS的意味。Rome可能是 sun 公司從自己某個子項目中抽離出來的,package和類的命名就象j2sdk一樣感覺規範。功能上支持RSS的所有版本及 Atom 0.3(Atom是和RSS類似的一種內容聚合的方式)。Rome 本身是提供API和功能實現.

更多RSS介紹:http://www.360doc.com/content/10/1224/09/1007797_80869844.shtml


二、實現思路

1.  http請求抓取RSS的內容。rss都是xml格式,通過home  jar裝配成對象。

先定義一個bean,請求的rss 內容都裝配成這種對象。字段根據你的項目要求來

public class RSSItemBean {
    private String title;
    private String author;
    private String uri;
    private String link;
    private String description;
    private Date pubDate;
    private String type;
    private String content;
    //省略 get  set
}

http請求代碼,這裏引用了 import com.sun.syndication.feed.synd.* ;下面的文件,請引入home.jar包

    /**
     *
     * @param url      rss 網站地址  比如:http://www.ithome.com/rss/
     * @return        所有文章對象
     * @throws Exception
     */
    public List<RSSItemBean> getRss(String url) throws Exception {
        URL feedUrl = new URL(url);//SyndFeedInput:從遠程讀到xml結構的內容轉成SyndFeedImpl實例
        SyndFeedInput input = new SyndFeedInput();//rome按SyndFeed類型生成rss和atom的實例,

        SyndFeed feed = input.build(new XmlReader(feedUrl));   //SyndFeed是rss和atom實現類SyndFeedImpl的接口
        List<SyndEntryImpl> entries = feed.getEntries();
        RSSItemBean item = null;
        List<RSSItemBean> rssItemBeans = new ArrayList<RSSItemBean>();
        for (SyndEntryImpl entry : entries) {
            item = new RSSItemBean();
            item.setTitle(entry.getTitle().trim());
            item.setType(feed.getTitleEx().getValue().trim());
            item.setUri(entry.getUri());
            item.setPubDate(entry.getPublishedDate());
            item.setAuthor(entry.getAuthor());
            rssItemBeans.add(item);
        }
        return rssItemBeans;
    }


到這裏rss解析就完畢了。新聞標題、文章地址、簡介都有了,很簡單吧,問題來了,新聞的正文還沒有呢?正文是不在rss內的,像百度新聞這種,只是做一個聚合,當你點擊新聞鏈接的時候,依然會鏈接到新聞的源網頁上面去。

某些時候,我們需要把新聞的正文也抓下來。難度不大,請接着往下看。



String url = entry.getUri();
item.setUri(url);

這個link就指向新聞的正文頁面,我們需要做的是從url獲取到源碼。這裏使用java 發起一個http請求,這裏涉及到java網絡操作的知識點,忘記了的再去補一下吧。 因爲每個網站的編碼都不一樣,有的用gbk,有的utf-8。中文在這個時候就比較糾結了,亂碼問題常常出現, 所以就有了這行代碼

 htmlContent = new String(bytes, pageEncoding);

這個pageEncoding,可以從讀取來源碼中找到,比如

content="text/html; charset=gb2312"
當然我是實現去要找的網站上找到的(肉眼去看的),gb2312對應GB2312;utf-8對應UTF-8.亂碼問題不多說,出了亂碼就是這裏的問題。

  /**
     * http 請求獲取到頁面的源碼
     * @param surl    正文url
     * @return    頁面源碼
     */
    public String getStaticPage(String surl) {
        String htmlContent = "";
        try {
            java.io.InputStream inputStream;
            java.net.URL url = new java.net.URL(surl);
            java.net.HttpURLConnection connection = (java.net.HttpURLConnection) url.openConnection();
            connection.connect();
            inputStream = connection.getInputStream();
            byte bytes[] = new byte[1024 * 4000];
            int index = 0;
            int count = inputStream.read(bytes, index, 1024 * 4000);
            while (count != -1) {
                index += count;
                count = inputStream.read(bytes, index, 1);
            }
            htmlContent = new String(bytes, pageEncoding);
            connection.disconnect();
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return htmlContent.trim();
    }


現在就把網頁的源代碼全部抓過來了,還不是我們想要的啊,我只要正文,其他東西都不要的。

看看我怎麼做的吧。




我用IT之家做的測試, 網站的右上角 有個"訂閱 "按鈕---->點擊



跳轉到了RSS 目錄。這些內容都被我抓取了,內容中的 紅色<link> 中的url 就指向新聞正文,複製鏈接,在瀏覽器中打開。如下圖,




紅色框中的內容 是不需要的,只需要綠色框中的內容。 我們抓來的源碼,就是一個string,只要找到文章的開始和結尾, 那不就把正文抓下來了嗎? 並且同一個網站,文章的內容的位置都一樣, 如果文章的父標籤是<div id="content"></div>    這樣我們就找到正文的開始了,正文的結尾也大多如此。 看下文


使用firebug 查看正文位置    我取的正文開始:<div class="post_content" id="paragraph">



正文結尾:<div class="share">



對應到代碼中,就是一個求子串的過程。如下

  /**
     * 根據url 獲取 正文內容
     *
     * @param url    指向正文的url地址 
     * @return         正文源碼
     */
    public String getContent(String url) {
        String src = getStaticPage(url);   //獲取所有源碼
        int startIndex = src.indexOf(startTag);   //開始標籤
        int endIndex = src.indexOf(endTag);        //結束標籤
         // System.out.println(src);
         // System.out.println(startTag+"\t"+endTag);
         //System.out.println(startIndex+"\t"+endIndex);
        if (startIndex!=-1 && endIndex !=-1) {
            return src.substring(startIndex, endIndex);
        }
        return "";
    }

就這樣 ,新聞的正文就抓過來了, 每個網站的 startTag和endTag 都不一樣,所以要分開對待。


rss正文抓取就這樣搞定了,下一篇文章,我會介紹針對不同網站,不同rss的正文抓取策略。也算是對自己工作的總結吧。

想認真研究的下載源碼吧。這個博客只寫了一些關鍵的代碼,有任何問題都可以直接聯繫我。


這個項目使用maven 開發,請加入maven支持或者導入相應的jar 

源碼的下載地址: http://download.csdn.net/detail/a442180673/6511981  簡單版本  正文抓取,未導入到數據

完整版本 :http://download.csdn.net/detail/a442180673/6523263     導入discuz 數據庫的實現





發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章