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原始碼下載