標籤:jsoup 網頁解析 select 資料抓取
最近使用了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 線上解析看看解析後的資料:
相信由上面兩個圖的說明,大家應該明白了代碼中是如何進資料列選取器的選取的。按照官網的說明,選取器非常強大,能夠進行綜合的選擇,大大簡化從網頁中擷取資料的複雜度。
至此,基本完成本博文想要說明的內容,如果有什麼錯誤,請大家不吝賜教。如果覺得還可以,請留個言,給個讚唄~~ ^_^謝謝~【握手】
著作權聲明:本文為博主原創文章,未經博主允許不得轉載。
android中使用JSOUP如何解析網頁資料詳述