在上篇博文《Web版RSS阅读器(三)——解析在线Rss订阅》中,已经提到了遇到的问题,这里再详细说一下。
在解析rss格式的订阅时,遇到的最主要的问题是,出现了“Server returned HTTP response code: 403 for URL: http://xxxxxx”的错误,百度一下就知道,这是在网站访问中很常见的一个错误,服务器理解客户的请求,但拒绝处理它。即拒绝访问!接着查资料,得知某些服务器(比如CSDN博客)拒绝java作为客户端进行对其的访问,所以在解析时,会抛异常。
不让访问怎么办,别怕,我们上有政策,下有对策。通过设置User-Agent来欺骗服务器,从而访问服务器。 connection.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)"); //用UA伪装访问连接对象
但是折腾了半天,发现只有修改rsslib4j.jar才能给连接对象设置UA。只好找源码修改一下了,N久之后,在Google Code上猎取到一个开源的项目newrsslib4j,它是在rsslib4j的基础上修改而来的,项目开源主页:http://code.google.com/p/newrsslib4j/。满怀欣喜的下载下来,结果发现,依旧有403的问题。一狠心,自己来做一个rsslib,然后就checkout了newrsslib4j的源码,自己动手改动。
1. 修改403 forbidden问题。
修改org.gnu.stealthp.rsslib包中的RssParser类的setXmlResource()方法,给URLConnection对象,添加UA。
/**
* Set rss resource by URL
* @param ur the remote url
* @throws RSSException
*/
public void setXmlResource(URL ur) throws RSSException{
try{
URLConnection con = u.openConnection();
//-----------------------------
//添加时间:2013-08-14 21:00:17
//人员:@龙轩
//博客:http://blog.csdn.net/xiaoxian8023
//添加内容:由于服务器屏蔽java作为客户端访问rss,所以设置User-Agent
con.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)");
//-----------------------------
con.setReadTimeout(10000);
String charset = Charset.guess(ur);
is = new InputSource (new UnicodeReader(con.getInputStream(),charset));
if (con.getContentLength() == -1 && is == null){
this.fixZeroLength();
}
}catch(IOException e){
throw new RSSException("RSSParser::setXmlResource fails: "+e.getMessage());
}
}
修改org.mozilla.intl.chardet包中的Charset类的guess()方法,注释掉原来的InputStream对象,创建URLConnection,设置User-Agent,通过URLConnection对象创建InputStream :
//judge from url
public static String guess(URL url) throws IOException {
//-----------------------------
//修改时间:2013-08-14 21:00:17
//人员:@龙轩
//博客:http://blog.csdn.net/xiaoxian8023
//修改内容:注释InputStream,创建URLConnection,设置User-Agent,通过URLConnection对象创建InputStream
//InputStream in = url.openStream();
URLConnection con = url.openConnection();
con.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)");
InputStream in = con.getInputStream();
//-----------------------------
return guess(in);
}
2. 添加获取文章摘要的方法
测试以后,发现Rss格式的订阅,居然没有提供一个获取内容摘要的方法。所以,继续修改。修改org.gnu.stealthp.rsslib包中的RssObject类,添加一个getSummary()方法,用来获取内容摘要:
//-----------------------------------
//添加时间:2013-08-14 19:32:15
//人员:@龙轩
//添加内容:添加getSummary()方法,返回文章摘要信息
/**
* Get the element's summary
* @return the summary
*/
public String getSummary(){
String summary = getDescription();
if (summary.length() >= 300) {
summary = summary.substring(0, 300);
}
String regEx_html = "\\s|<[^>]+>|&\\w{1,5};"; // 定义HTML标签和特殊字符的正则表达式
Pattern pattern = Pattern.compile(regEx_html,Pattern.CASE_INSENSITIVE);
Matcher matcher = pattern.matcher(summary);
summary = matcher.replaceAll(""); // 过滤script标签
if (summary.length() >= 100) {
summary = summary.substring(0, 100);
}
summary = summary + "...";
return summary;
}
//添加结束-----------------------------------------------
3. 解决解析不完全问题
网易博客可以很好的解析出博客的link,language等节点,但是csdn、某些新闻资讯网站则不行。花了很长的时间去找问题,终于在不经意间,发现网易的博客节点的排列顺序与别的不一样,link,language等节点排在image节点上面的,而csdn则是在image的下面(如图),程序在解析时,先解析channel下的节点,写入到channel中,读取到image,则标记解析channel的变量为false,然后开始解析image节点下的内容。解析完毕以后,又要去解析channel节点下的link时,channel标记已经为false了,不能再继续解析,所以总是返回null。
修改方案也很简单,就是所有标记解析channel为false的节点,在解析完毕该节点后,重新标记解析channel为true,这样就可以继续解析channel节点下的其他值 。具体修改操作:查看org.gnu.stealthp.rsslib包的RSSHandler类的startElement()方法,看看谁执行了 reading_chan = false; 这句代码。然后在endElement()方法中,重新设置 reading_chan
= true; 即可:
/**
* Receive notification of the end of an element
* @param uri The Namespace URI, or the empty string if the element has no Namespace URI or if Namespace processing is not being performed.
* @param localName The local name (without prefix), or the empty string if Namespace processing is not being performed
* @param qName The qualified name (with prefix), or the empty string if qualified names are not available
*/
public void endElement(String uri,
String localName,
String qName){
String data = buff.toString().trim();
if (qName.equals(current_tag)){
data = buff.toString().trim();
buff = new StringBuffer();
}
if (reading_chan)
processChannel(qName,data);
if (reading_item)
processItem(qName,data);
if (reading_image)
processImage(qName,data);
if (reading_input)
processTextInput(qName,data);
if (tagIsEqual(qName,CHANNEL_TAG)){
reading_chan = false;
chan.setSyndicationModule(sy);
}
if (tagIsEqual(qName,ITEM_TAG)){
reading_item = false;
//-----------------------------------------
//添加时间:2013-08-14 21:00:17
//人员:@龙轩
//博客:http://blog.csdn.net/xiaoxian8023
//添加内容:重新允许解析channel
reading_chan = true;
//添加结束---------------------------------
chan.addItem(itm);
}
if (tagIsEqual(qName,IMAGE_TAG)){
reading_image = false;
//-----------------------------------------
//添加时间:2013-08-14 21:00:17
//人员:@龙轩
//博客:http://blog.csdn.net/xiaoxian8023
//添加内容:重新允许解析channel
reading_chan = true;
//添加结束---------------------------------
chan.setRSSImage(img);
}
if (tagIsEqual(qName,SEQ_TAG)){
reading_seq = false;
chan.addRSSSequence(seq);
}
if (tagIsEqual(qName,TEXTINPUT_TAG)){
reading_input = false;
//-----------------------------------------
//添加时间:2013-08-14 21:00:17
//人员:@龙轩
//博客:http://blog.csdn.net/xiaoxian8023
//添加内容:重新允许解析channel
reading_chan = true;
//添加结束---------------------------------
chan.setRSSTextInput(input);
}
}
至此,修改的就差不多了,打开一下org.javali.util.test包的RssNewsFetcher类,修改一下测试列表和方法:
package org.javali.util.test;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import org.gnu.stealthp.rsslib.RSSChannel;
import org.gnu.stealthp.rsslib.RSSException;
import org.gnu.stealthp.rsslib.RSSHandler;
import org.gnu.stealthp.rsslib.RSSItem;
import org.gnu.stealthp.rsslib.RSSParser;
public class RssNewsFetcher {
/**
* rss订阅列表
*/
private final static String[] rssArr = new String[] {
//"http://news.baidu.com/n?cmd=1&class=civilnews&tn=rss",
"http://xiaoxian100.blog.163.com/rss",
"http://blog.csdn.net/xiaoxian8023/rss/list"
};
/**
* 测试解析rss订阅
* @throws IOException
*/
public void testFetchRssNews() throws IOException {
for (int i = 0; i < rssArr.length; i++) {
try {
//获取rss订阅地址
URL url = new URL(rssArr[i]);
RSSHandler handler = new RSSHandler();
//解析rss
RSSParser.parseXmlFile(url, handler, false);
//获取Rss频道信息
RSSChannel ch = handler.getRSSChannel();
System.out.println("---------------------------------------------");
System.out.println("博客标题:" + ch.getTitle());
System.out.println("博客链接:" + ch.getLink());
System.out.println("博客描述:" + ch.getDescription());
System.out.println("博客语言:" + ch.getLanguage());
System.out.println("发布时间:" + ch.getPubDate());
System.out.println("图片地址:" +ch.getRSSImage().getUrl());
System.out.println("图片指向:" +ch.getRSSImage().getLink());
System.out.println("共有文章数目为:" + ch.getItems().size());
// for(i=0;i<ch.getItems().size();i++){
for(int j=0;j<1;j++){ //这里为了方便测试,只取一次循环,真实使用时,需选用上面那句代码
RSSItem item = (RSSItem)ch.getItems().get(j);
System.out.println("文章标题:" + item.getTitle());
System.out.println("文章摘要:" + item.getSummary());
//System.out.println("文章正文:" + item.getDescription());
//这里为了演示方便,我取正文的前100个字符,真实使用时,需选用上面那句代码
System.out.println("文章正文:" + item.getDescription().substring(0, 100));
System.out.println("文章链接:" + item.getLink());
System.out.println("发表时间:" + item.getPubDate());
System.out.println("文章作者:" + item.getAuthor());
System.out.println("最新修改:" + item.getDate());
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (RSSException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) throws IOException{
RssNewsFetcher fetcher = new RssNewsFetcher();
fetcher.testFetchRssNews();
}
}
测试结果如图:
已经修改的差不多了,下一步就是做成jar,以供本项目使用。步骤很简单。右键项目,选择“导出”→“Java”→“jar文件”,下一步,把右侧的勾全去掉,然后设定一下jar的生成路径,点击“完成”即可。javadoc生成方式差不多,可以参考这里。
手痒了么?快来试试看吧。当然,现在做的myrsslib4j 跟rsslib4j一样,仅仅支持rss格式的博客。下篇博客给大家奉献修改过的rome——myrome,它很好的支持了rss和atom 2种格式的博客。此阅读器会以myrome来解析在线的订阅信息,敬请期待吧。
加句题外话,为了更好的与大家分享,我在Google Code中上传了myrsslib4j的源代码。项目主页:https://code.google.com/p/myrsslib4j/。个人能力所限,难免会有瑕疵,欢迎大家多多指正。
分享到:
相关推荐
Android综合案例——RSS阅读器实源代码+讲解
web版Rss阅读器源码
rss阅读器与 XML解析 XML RSS 阅读器 Winfom ASP.NET rss阅读器与 XML解析 XML RSS 阅读器 Winfom ASP.NET rss阅读器与 XML解析 XML RSS 阅读器 Winfom ASP.NET rss阅读器与 XML解析 XML RSS 阅读器 Winfom ASP.NET ...
基于web的rss阅读器
Google.Android开发入门与实战第12章.Android综合案例一——RSS阅读器实例
基于WEB的RSS阅读器,用C#实现CBC的对称密码,(加上高级加密标准(AES)的实现)
我们希望通过我们RSS阅读管理器这样一个软件,为用户提供关于RSS方面的尽可能多的帮助与支持,以帮助用户运用该软件通过RSS订阅的方式,更方便,更实用的获得信息,处理信息,储存信息,管理信息,传递信息。
前几天想找VC编写的RSS阅读器,找了很久没有,找到的都是C#以及其它的,就自己研究一下,其重点无非就是把XML中的RSS信息读取出来。
基于JAVA SWING的RSS阅读器,使用JDOM解析本地XML文件
基于ASP.NET 3.5 AJAX客户端框架开发Web版RSS阅读器
新浪RSS 新闻阅读器源码啊 android
RSS阅读器,rss新闻在线阅读,XML,Ajax
Rss阅读器编码Rss阅读器编码Rss阅读器编码Rss阅读器编码Rss阅读器编码Rss阅读器编码
一个基于新浪RSS的android RSS阅读器源码 虽然不成熟 但是基本功能已经实现 可以学习学习
周博通RSS阅读器.周博通RSS阅读器.周博通RSS阅读器.周博通RSS阅读器.周博通RSS阅读器.周博通RSS阅读器.周博通RSS阅读器.周博通RSS阅读器.
Android源码——RSS阅读器的源码.zip
如何基于iPhone 设计一个简单的RSS阅读器应用 How To Make A Simple RSS Reader iPhone App Tutorial
安卓Android源码——RSS阅读器的源码.zip
Android源码——RSS阅读器的源码.7z