JavaでRSSの広告削除してみる(3) Removing Ads from Rss by Java

RSSから広告削除する、簡単なアプリをつくってみようかと思っています。
3回に分けて書いています。I write this in 3-posts.

第1回 JavaでRSS受信する。 Getting RSS by Java
第2回 HTMLパーサを使う。 Using HTML-parser
第3回 RSSを出力してみる。 Outputting RSS

今回は第3回めです。This is 3rd post.

————————————————————–
使っている環境

Java JDK1.6.0_35(64bit版)
Google App Engine SDK for Java 1.7.1
Eclipse IDE for Java EE Developers_ Juno (4.2)64Bit版
The Google Plugin for Eclipse, for Eclipse 3.8/4.2 (Juno)

ROME 1.0
JDOM 1.1.3
( Xerces 2.11.0 )
jsoup-1.7.2


(1)はじめに Introduction
クラスを作ってその中で「RSS読込→広告削除→RSS出力」の処理を行いたいと思います。
RSS読込・広告削除は、前回・前々回のエントリーで行ったので、今回は、まずRSS出力を試してみます。

In my Class, I would try to do entire process of “RSS-reading”, “removing-Ads”, and “RSS-outputting”.
I did “RSS-reading” and “removing-Ads” in previously post. Today, I will try to do “RSS-outputting” first.


(2)RSSの出力 Outputting RSS
SyndFeedOutput クラスのoutputString メソッドで、XMLを出力できます。
ROMEでRSSを読込んだ時のfeedを、outputString メソッドに引き渡す感じになります。
You could output XML by using outputString method of SyndFeedOutput class.
You execute outputString method with the “feed” that made by ROME .
(参考) 技術への名残り: JavaでRSSを作成(ROME利用)

        SyndFeedOutput output = new SyndFeedOutput();
        String outputRss = output.outputString(feed);

(3)コーディング Coding
CrawlRssクラスを作って、その中で処理を行うことにしました。
処理の流れはこんな感じ。
I thought that I would make “CrawlRss class” and do what’s I need.
I will show you my plan(below)

・setUrlメソッド
接続先URLをセットします。Setting URL

・getRssFeedメソッド
RSSを読込みます。このメソッドは、取得したデータ(SyndFeed型)を返します。
Reading RSS. this method will return that data as SyndFeed-type.

・doFilterメソッド
RSSのタイトルが、広告かどうかをチェックして、広告の場合は削除します。
RSSのdescriptionをチェックして、中に含まれる広告を削除します。
(広告かどうか判別する処理は、今後も増えていくため、別メソッドに書いています。
タイトルのチェックはtitleIsAdsメソッド、descriptionのチェックはhtmlParsingメソッドの中で、具体的なチェックを行っています。)

Checking “Title” of RSS-entry. and If the Title is Ads, it’s remove the RSS-entry.
Checking “description” of RSS-entry. And it’s remove Ads in the description.

・outputRssメソッド
RSSfeedデータから、RSSを出力します。String型でXMLデータを返します。
This output RSS generated from RSSfeed-data. This return RSS as XML-data.

CrawlRss.java

package rssReader;

import java.io.IOException;
import java.net.URL;
import java.util.Iterator;
import java.util.List;

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

import com.sun.syndication.feed.synd.SyndEntry;
import com.sun.syndication.feed.synd.SyndFeed;
import com.sun.syndication.io.FeedException;
import com.sun.syndication.io.SyndFeedInput;
import com.sun.syndication.io.SyndFeedOutput;
import com.sun.syndication.io.XmlReader;
import com.sun.syndication.feed.synd.SyndContent; 

public class CrawlRss {
    private String url;

    /** 
     * XXX 
     *
     * @param  url  URL for getting RssFeed
     * @param  feed  RssFeed generated by ROME
     */
    public void setUrl(String url) {
        this.url = url;
    }

    public String getUrl() {
        return this.url;
    }

    public SyndFeed getRssFeed() throws IOException  {
        SyndFeed feed = null;

        if ( this.url == null ){
            System.out.println("Parameter( url ) didn't set.");
            return null;
        }else{
            try {
                URL feedUrl = new URL(this.url);
                XmlReader reader = new XmlReader(feedUrl.openStream());
                    SyndFeedInput input = new SyndFeedInput();
                    feed = input.build(reader);
                reader.close();

            } catch (FeedException e) {
                e.printStackTrace();
            }
        }

        return feed;
    }

    public SyndFeed doFilter(SyndFeed feed){

        List<SyndEntry> entries = feed.getEntries();
        Iterator<SyndEntry> itr = entries.iterator();

        while (itr.hasNext()){
            SyndEntry entry = itr.next();

            // Removing Ads from Title
            String title = entry.getTitle();
            if ( titleIsAds(title)) {
                itr.remove();
                continue;
            }

            // Removing Ads from Desc
            SyndContent desc = entry.getDescription();

            if (desc != null){
                String html_parsed = htmlParsing(desc.getValue());
                desc.setValue(html_parsed);
            }
        }

        return feed;
    }

    public boolean titleIsAds(String title){
        if ( title.startsWith("PR:")) {
            return true;
        }else{
            return false;
        }

    }

    public String htmlParsing(String html){

        Document doc = Jsoup.parse(html, "UTF-8");
        Elements links = doc.getElementsByTag("a");

        for (Element link : links) {
            String href = link.attr("href");

            if ( href.indexOf("rss.rssad.jp/rss/ad/") != -1 ) {
                link.remove();
            }
        }

        Elements imgs = doc.getElementsByTag("img");

        for (Element img : imgs) {
            String width = img.attr("width");
            String height = img.attr("height");

            if ( width.equals("1") && height.equals("1") ) {
                img.remove();
            }
        }

        String bodies_str = doc.getElementsByTag("body").toString();
        bodies_str = bodies_str.replaceFirst("^<body>\n", "");
        bodies_str = bodies_str.replaceFirst("\n</body>$", "");
        bodies_str = bodies_str.replaceFirst("^ +", "");

        return bodies_str;
    }

    public String outputRss(SyndFeed feed) throws FeedException{
        SyndFeedOutput output = new SyndFeedOutput();
        String outputRss = output.outputString(feed);

    return outputRss;
    }
}

実際に動かす場合は、こうします。
Here is my code to use the Class.

package rssReader.test;

import java.io.IOException;

import com.sun.syndication.feed.synd.SyndFeed;
import com.sun.syndication.io.FeedException;

import rssReader.CrawlRss;

public class unitTest_output_XML {
    public static void main(String[] args) throws IOException, FeedException {

        CrawlRss crss = new CrawlRss();

        crss.setUrl("http://rss.rssad.jp/rss/gihyo/feed/rss2");
        // crss.setUrl("http://jp.techcrunch.com/feed/");
        // crss.setUrl("http://wired.jp/rssfeeder/");

        //System.out.println("Access to : " + crss.getUrl() + "\n\n");

        SyndFeed feed = crss.getRssFeed();

        if (feed == null){
            System.out.println("Exit");
            System.exit(-1);
        }

        feed = crss.doFilter(feed);

        String outputRss = crss.outputRss(feed);
        System.out.println(outputRss);

    }

}

こんな感じでXMLが返ってきます
That code will return these XML(below).

<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0">
  <channel>
    <title>gihyo.jp:総合</title>
    <link>http://gihyo.jp/</link>
    <description>gihyo.jp(総合)の更新情報をお届けします</description>
    <language>ja-jp</language>
    <copyright>技術評論社 2013</copyright>
   :   :

    <item>
      <title>第6回 Capacity Scheduler による複数ジョブの同時実行 ── halookで始めるHadoop/HBaseトラブルシューティング</title>
      <link>http://rss.rssad.jp/rss/artclk/47ghQF72z411/6d70ced8b37632c22bd6add0ae4e4982?ul=tMUp6phKmaEl5PP2lXYGvZcEI0UboxMPKoYv1ONSRKgTtDvugPJtMP3M.QKxrTI5bkjb3.g</link>
      <description>今回は,Capacity Schedulerを使った場合について,複数ジョブの同時実行時の挙動を見てみましょう。</description>
   :   :

    </item>
    <item>
   :   :

今のところ、TechCrunch Japan、WIRED.jp、gihyo.jp のRSSfeedから広告削除できるようになっています。もうちょっと、チェックの条件を増やして、たいていのRSSに対応できるような形にできればいいなと、思っています。
This code supports removing Ads from RSS of “TechCrunch Japan”, “WIRED.jp” “gihyo.jp”.
I hope that I would add more rule to the code for removing Ads, so it could support more RSS.

それをGoogleAppEngine上で動かすようにすれば、APIとして公開できるかな。(同じようなサービスは、たくさんあるけど(笑))
And then,  I would deploy the code on GAE as an API. (There is many Service for Romoving Ads  from RSS 🙂  )

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s