1. 程式人生 > >Android 資料抓取——線上音樂播放器的實現

Android 資料抓取——線上音樂播放器的實現

前言: 相信很多同學學習android都開做過播放器一類的小玩意吧,但是苦於沒有伺服器提供資料,因而只能做個本地播放器,今天,這篇文章就是通過資料抓取,實現沒有伺服器,依然可以線上搜尋和播放音樂!

首先,貼上我的最終實現效果:
這裡寫圖片描述

因為資料是從蝦米搜尋頁抓過來的,所以我把蝦米logo加上去了,請大家忽略,下面來講基本思路,首先蝦米有這樣一個隱藏的API:

所以,我們只需要知道歌曲ID就能獲得歌曲資訊了,一切都成為可能了,那麼問題來了! 我們怎麼獲取歌曲ID呢?————沒錯,今天的主角登場
——Jsoup 我們用它去蝦米搜尋結果抓歌曲ID!
首先我們看看蝦米的搜尋網址:
這裡寫圖片描述

然後我們對頁面審查原始碼,我們可以清楚的發現,所有搜尋結果是放在一個 名為 track_list的 table中(也就是html表格中),如圖所示:
這裡寫圖片描述


我們繼續往裡面看:
在一個chkbox的 標籤裡面發現了一串數字,測試之前的我們的介面,果然是相符的,id就是它了!
這裡寫圖片描述

接下來就是寫程式碼了!
首先我們匯入jsoup的jar包到我們的專案中 Jsoup下載地址:
Jsoup 需要新增網路許可權

/** 搜尋關鍵字地址 */
    public static String KEY_SEARCH_URL = "http://www.xiami.com/search/song?key=";
    /** ID介面地址 */
    public static String ID_SEARCH_URL = "http://www.xiami.com/song/playlist/id/"
; /** * 抓取歌曲id * * @param 搜尋關鍵詞 * @param listener * 完成監聽 */ public static void getIds(String input, OnLoadSearchFinishListener listener) { List<String> allIds = new ArrayList<String>(); String key = deCondeKey(input);// 解析使用者輸入關鍵字為 UTF-8
Document document = null; try { document = Jsoup.connect(KEY_SEARCH_URL + key).get();// jsoup連線最終拼接而成的請求字串 Elements elements = document.getElementsByClass("track_list");// 選擇類標籤 if (elements.size() != 0) { Elements all = elements.get(0).getElementsByClass("chkbox"); int size = all.size(); for (int i = 0; i < size; i++) { String id = all.get(i).select("input").attr("value"); if (!StringUtils.isEmpty(id)) { allIds.add(id);// 不為空的話加入id list中,便於初次抓取完以後統一請求 } } if (listener != null) { if (allIds.size() == 0) { listener.onLoadFiler();// id list大小為0 說明沒有獲取到資料,抓取失敗 } else { // 統一請求id介面地址進行再次抓取 listener.onLoadSucess(getOnlineSearchList(allIds)); } } } } catch (IOException e) { listener.onLoadFiler(); e.printStackTrace(); } }

核心邏輯解釋:
首先我們用Jsoup.connect(url).get()方法獲得一個document物件,然後用document物件去篩選我們先分析的那個表也就是track_list 返回一個Elements物件,我們在此篩選 chkbox,依然返回一個Elements 物件,由於歌曲有很多首,我們需要遍歷一下,再選擇input 標籤獲得我們的id

Elements elements = document.getElementsByClass("track_list");// 選擇類標籤
Elements all = elements.get(0).getElementsByClass("chkbox");
int size = all.size();
                for (int i = 0; i < size; i++) {
                    String id = all.get(i).select("input").attr("value");
                    }

上面方法就能獲得我們的歌曲id,我們將它們封裝在一個list中,在抓取id完成以後,我們依次取出list中的id去請求api 然後封裝在一個list:中,便於在listview中展示:

Music.java實體類

import java.io.Serializable;

public class Music implements Serializable {

    /**
     * 
     */
    private static final long serialVersionUID = 1L;
    /** 歌名 */
    private String musciName;
    /** 歌手名 */
    private String airtistName;
    /** 歌曲路徑 */
    private String path;
    /** 專輯名 */
    private String albumName;
    /** 小圖URL */
    private String smallAlumUrl;
    /** 大圖URL */
    private String bigAlumUrl;
    /** 歌曲id */
    private String musicId;
    /** 歌詞地址 */
    private String lrcUrl;

    public String getMusciName() {
        return musciName;
    }

    public void setMusciName(String musciName) {
        this.musciName = musciName;
    }

    public String getAirtistName() {
        return airtistName;
    }

    public void setAirtistName(String airtistName) {
        this.airtistName = airtistName;
    }

    public String getPath() {
        return path;
    }

    public void setPath(String path) {
        this.path = path;
    }

    public String getAlbumName() {
        return albumName;
    }

    public void setAlbumName(String albumName) {
        this.albumName = albumName;
    }

    public String getSmallAlumUrl() {
        return smallAlumUrl;
    }

    public void setSmallAlumUrl(String smallAlumUrl) {
        this.smallAlumUrl = smallAlumUrl;
    }

    public String getBigAlumUrl() {
        return bigAlumUrl;
    }

    public void setBigAlumUrl(String bigAlumUrl) {
        this.bigAlumUrl = bigAlumUrl;
    }

    public String getMusicId() {
        return musicId;
    }

    public void setMusicId(String musicId) {
        this.musicId = musicId;
    }

    public String getLrcUrl() {
        return lrcUrl;
    }

    public void setLrcUrl(String lrcUrl) {
        this.lrcUrl = lrcUrl;
    }

}
/**
     * 根據id 獲取歌曲資料
     * 
     * @param ids 封裝id 的list
     *           
     * @return 封裝好的list<music> 用於listview展示
     */
    private static List<Music> getOnlineSearchList(List<String> ids) {
        List<Music> musicList = new ArrayList<Music>();
        int idSize = ids.size();
        for (int i = 0; i < idSize; i++) {
            String postUrl = ID_SEARCH_URL + ids.get(i);
            try {
                Document d = Jsoup.connect(postUrl).get();// 連線相應ID的介面地址
                Elements element = d.select("trackList");
                for (Element e : element) {
                    Music music = new Music();
                    music.setMusicId(ids.get(i));
                    music.setMusciName(getSubString(e.select("title").text()));
                    music.setAirtistName(e.select("artist").text());
                    music.setSmallAlumUrl(e.select("pic").text());
                    music.setBigAlumUrl(e.select("album_pic").text());
                    music.setLrcUrl(e.select("lyric").text());
                    music.setAlbumName(e.select("album_name").text());
                    // 對加密過後的歌曲線上地址進行解密
                    music.setPath(StringUtils.decodeMusicUrl(e.select(
                            "location").text()));
                    musicList.add(music);// 資料獲取成功 封裝入list
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return musicList;
    }

這邊 歌曲地址是經過加密的,我們用的時候要先解密,演算法在demo裡面。
在抓取完資料獲得list以後,我只需寫一個adpter,將資料用listview展示即可,
效果如下:
這裡寫圖片描述

這裡大功告成,線上搜尋列表完成,要實現線上播放,只需要在listview點選的時候 使用 MediaPlayer.setDataSource(歌曲線上地址)即可,獲得了線上地址,下載實現起來也很簡單(自己寫,或者藉助第三方框架 xutils等均可)在這裡本文主要講核心抓取邏輯,這裡就不做闡述了。
注意事項:
getIds()方法是網路訪問,因此需要在子執行緒中呼叫,在主執行緒呼叫會報錯,在資料獲取完成以後,通過handler 再給listview設定adpter即可,具體程式碼大家請參考Demo.
資料抓取畢竟是拿別人網站上的資料,僅供學習使用,請不要用於任何商業用途!
有任何問題請留言或者私信!
點此Demo原始碼下載