最近使用了Jsoup,感觉还是挺简单,挺方便的,轻而易举地抓取网页源码,分析获取各个标签所需的东西。
这几天在搞一个音乐播放器的小项目,其中使用到了就是使用JSOUP进行页面数据的获取,获取网页的歌曲列表,并对歌曲的链接进行加载,以便实现歌曲下载和歌词的下载。搞好之后,就会跟着写几篇博文,分享给大家。本博文主要说明android中使用jsoup如何进行网页数据的获取。
具体可看下面各个相关例子:
Jsoup下载地址:
http://jsoup.org/download
jsoup开发指南,jsoup中文使用手册,jsoup中文文档:
http://www.open-open.com/jsoup/
中文文档非常好,说明也非常详细,网上面好多都是拷贝这个中文文档发的博文。我刚开始的时候看了,但是一直对于其中的选择器所选择的内容一直不知道如何选择。这个问题好多博文没有说明。
本博文不再说明关于jsoup的用法之类的api了,中文文档说明的很明白了,主要说明如何进行解析网页数据。本博文解析的案例主要是解析网页中的歌曲列表,网页地址是:http://music.baidu.com/top/new/?pst=shouyeTop
网页界面:
这个网页是百度音乐的网页,收录了新歌排行榜,项目中就是对这个网页进行解析获取歌曲列表的。
先上图,android实现的界面如下:
解析网页然后,获取网页数据,加载列表,展示给用户。
下面开始具体实现:
1 歌曲对象类
/**
* 2015年8月15日 15:51:26
* 博文地址:http://blog.csdn.net/u010156024
* 歌曲对象类
*/
public class SearchResult implements Serializable {
private static final long serialVersionUID = 0X00000001l;
private String musicName;
private String url;
private String artist;
private String album;
public String getArtist() {
return artist;
}
public void setArtist(String artist) {
this.artist = artist;
}
public String getMusicName() {
return musicName;
}
public void setMusicName(String musicName) {
this.musicName = musicName;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getAlbum() {
return album;
}
public void setAlbum(String album) {
this.album = album;
}
}
上面是一个歌曲对象类,非常简单的javabean。不多说了。
2 使用jsoup进行页面数据解析
/**
* 2015年8月15日 15:54:43
* 博文地址:http://blog.csdn.net/u010156024
* 该类完成功能: 有URL链接解析出推荐的歌曲列表
*/
public class SongsRecommendation {// http://music.baidu.com/top/new/?pst=shouyeTop
private static final String URL = "http://music.baidu.com"
+ "/top/new/?pst=shouyeTop";
private static SongsRecommendation sInstance;
/**
* 回调接口,传递数据给Activity或者Fragment
* 非常好用的数据传递方式
*/
private OnRecommendationListener mListener;
private ExecutorService mThreadPool;
public static SongsRecommendation getInstance() {
if (sInstance == null)
sInstance = new SongsRecommendation();
return sInstance;
}
private Handler mHandler = new Handler() {
@SuppressWarnings("unchecked")
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case Constants.SUCCESS:
if (mListener != null)
mListener
.onRecommend((ArrayList<SearchResult>) msg.obj);
break;
case Constants.FAILED:
if (mListener != null)
mListener.onRecommend(null);
break;
}
}
};
@SuppressLint("HandlerLeak")
private SongsRecommendation() {
// 创建单线程池
mThreadPool = Executors.newSingleThreadExecutor();
}
/**
* 设置回调接口OnRecommendationListener类的对象mListener
*
* @param l
* @return
*/
public SongsRecommendation setListener(OnRecommendationListener l) {
mListener = l;
return this;
}
/**
* 真正执行网页解析的方法
* 线程池中开启新的线程执行解析,解析完成之后发送消息
* 将结果传递到主线程中
*/
public void get() {
mThreadPool.execute(new Runnable() {
@Override
public void run() {
ArrayList<SearchResult> result = getMusicList();
if (result == null) {
mHandler.sendEmptyMessage(Constants.FAILED);
return;
}
mHandler.obtainMessage(Constants.SUCCESS, result)
.sendToTarget();
}
});
}
private ArrayList<SearchResult> getMusicList() {
try {
/**
* 一下方法调用请参考官网
* 说明:timeout设置请求时间,不宜过短。
* 时间过短导致异常,无法获取。
*/
Document doc = Jsoup
.connect(URL)
.userAgent(
"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36"
+ " (KHTML, like Gecko) Chrome/42.0.2311.22 Safari/537.36")
.timeout(60 * 1000).get();
//select为选择器,请参考官网说明
Elements songTitles = doc.select("span.song-title");
Elements artists = doc.select("span.author_list");
ArrayList<SearchResult> searchResults = new ArrayList<SearchResult>();
for (int i = 0; i < songTitles.size(); i++) {
SearchResult searchResult = new SearchResult();
Elements urls = songTitles.get(i).getElementsByTag("a");
searchResult.setUrl(urls.get(0).attr("href"));
searchResult.setMusicName(urls.get(0).text());
Elements artistElements = artists.get(i).getElementsByTag("a");
searchResult.setArtist(artistElements.get(0).text());
searchResult.setAlbum("最新推荐");
searchResults.add(searchResult);
}
return searchResults;
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
/**
* 回调接口 获取数据之后,通过该接口设置数据传递
*/
public interface OnRecommendationListener {
public void onRecommend(ArrayList<SearchResult> results);
}
}
上面这个类就是实现也对网页数据的解析,解析完成之后,通过handler传递给主线程,主线程中handmessage方法中,通过回调接口,将数据传递给调用该类的activity或者fragment。
一般的博文大部分到此就为止了,因为关键部分都已经给大家说明了。但是我想说的是在使用jsoup进行解析的时候,
//select为选择器,请参考官网说明
Elements songTitles = doc.select("span.song-title");
Elements artists = doc.select("span.author_list");
ArrayList<SearchResult> searchResults = new ArrayList<SearchResult>();
for (int i = 0; i < songTitles.size(); i++) {
SearchResult searchResult = new SearchResult();
Elements urls = songTitles.get(i).getElementsByTag("a");
searchResult.setUrl(urls.get(0).attr("href"));
searchResult.setMusicName(urls.get(0).text());
Elements artistElements = artists.get(i).getElementsByTag("a");
searchResult.setArtist(artistElements.get(0).text());
searchResult.setAlbum("最新推荐");
searchResults.add(searchResult);
}
这部分代码最为关键,而其中
Elements songTitles = doc.select(“span.song-title”);
Elements artists = doc.select(“span.author_list”);
这两句代码中的span.song-title 、span.author_list怎么选的呢?刚开始的时候真是不理解,现在我就带着大家看看如何进行选择的。如果你读到这里已经明白了,那就不用往下看了。如果不明白,请继续。。。
首先到网页http://music.baidu.com/top/new/?pst=shouyeTop,使用浏览器查看源码,截图:
通过查看源码我们知道,上面所选择的span.song-title、span.author_list都是源码中的。
下面我们再到http://try.jsoup.org/ 网页,进行尝试在线解析,页面截图:
下面输入http://music.baidu.com/top/new/?pst=shouyeTop 在线解析看看解析后的数据:
相信由上面两个图的说明,大家应该明白了代码中是如何进行选择器的选取的。按照官网的说明,选择器非常强大,能够进行综合的选择,大大简化从网页中获取数据的复杂度。
至此,基本完成本博文想要说明的内容,如果有什么错误,请大家不吝赐教。如果觉得还可以,请留个言,给个赞呗~~ ^_^谢谢~【握手】