android中使用JSOUP如何解析网页数据详述

时间:2022-10-31 10:02:02

最近使用了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中使用JSOUP如何解析网页数据详述

这个网页是百度音乐的网页,收录了新歌排行榜,项目中就是对这个网页进行解析获取歌曲列表的。

先上图,android实现的界面如下:
android中使用JSOUP如何解析网页数据详述

解析网页然后,获取网页数据,加载列表,展示给用户。
下面开始具体实现:
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,使用浏览器查看源码,截图:
android中使用JSOUP如何解析网页数据详述
通过查看源码我们知道,上面所选择的span.song-title、span.author_list都是源码中的。

下面我们再到http://try.jsoup.org/ 网页,进行尝试在线解析,页面截图:
android中使用JSOUP如何解析网页数据详述

下面输入http://music.baidu.com/top/new/?pst=shouyeTop 在线解析看看解析后的数据:
android中使用JSOUP如何解析网页数据详述

android中使用JSOUP如何解析网页数据详述

相信由上面两个图的说明,大家应该明白了代码中是如何进行选择器的选取的。按照官网的说明,选择器非常强大,能够进行综合的选择,大大简化从网页中获取数据的复杂度。

至此,基本完成本博文想要说明的内容,如果有什么错误,请大家不吝赐教。如果觉得还可以,请留个言,给个赞呗~~ ^_^谢谢~【握手】