Android使用jsoup解析音乐网站获取歌名与歌手名显示在ListView上

最近这段时间老师让我们学生自己去做个项目,我自己选择做一个音乐播放器,因为这个比较简单,上手也比较容易,老师教的知识基本都用得上。

我自己就无聊跑去弄个网络获取歌单,当然也只是歌单,并不能实现播放功能,不过也学到了一些知识。获取网络的歌曲名与歌手名,我是这样弄的,我参考了很多前辈的用法,大多数的前辈们基本都是使用jsoup这个包去解析一些音乐网站,然后再获取想要的信息,这里我对我学到的知识做一下总结:


首先我们需要去导一下jsoup的jar包,在Android Studio中导入的方法:

第一种方法:可以直接在app文件夹下的build.gradle中的

dependencies{

compile 'org.jsoup:jsoup:1.10.3' //版本看情况
 }

第二种方法:可以直接去https://jsoup.org/download 这个网址下载jsoup的jar包,下载完后,

Android使用jsoup解析音乐网站获取歌名与歌手名显示在ListView上Android使用jsoup解析音乐网站获取歌名与歌手名显示在ListView上

然后对着这个jar包点击右键 找到Add As Library,软件就会帮你导入这个jar包啦


第三种方法:这种最为方便,可以直接在Android Studio中下载

Android使用jsoup解析音乐网站获取歌名与歌手名显示在ListView上


这些准备工作基本都做完了,下面我们就开始进入项目中:


首先我们先把他的布局给弄出来,不弄布局哪里会显示哦。。

布局文件名:activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.caijixieshou.NetMusic.MainActivity">


    <ListView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/net_song_listview"
        />


</LinearLayout>


弄好布局后,我们创建在java文件夹下创建一个包叫domain,在该包下创建一个Bean类NetSongsResults来封装歌曲的信息

public class NetSongsResults {
    private String MusicName;//歌名
    private String Artist;//歌手名
    private String Album;//专辑


    //用系统自带的Getter和Setter封装


    public String getMusicName() {
        return MusicName;
    }


    public void setMusicName(String musicName) {
        MusicName = musicName;
    }


    public String getArtist() {
        return Artist;
    }


    public void setArtist(String artist) {
        Artist = artist;
    }


    public String getAlbum() {
        return Album;
    }


    public void setAlbum(String album) {
        Album = album;
    }


    //这里用系统生成的toString方法为了方便打印信息
    @Override
    public String toString() {
        return "NetSongsResults{" +
                "MusicName='" + MusicName + '\'' +
                ", Artist='" + Artist + '\'' +
                ", Album='" + Album + '\'' +
                '}';
    }

}


弄好了bean文件后,我们还在java文件夹下创建一个工具util包,在该包下创建一个解析类JsoupUtils,该类用来解析音乐网站

public class JsoupUtils {
    private static JsoupUtils instance;
    //这里用单例的方式,为了方便使用
    public static JsoupUtils getInstance(){
        if (instance == null){
            instance = new JsoupUtils();
        }
        return instance;
    }


    public void getMusic(final String url, final String title,
                         final String artist, final ArrayList<NetSongsResults> datalist,
                         final CallBack mCallBack){
        //因为联网解析网页属于一种耗时操作,所以我们需要在这里另起一个线程
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    /**这里用Jsoup去调用这一些一系列的方法,这些基本都是固定写法
                     * 其中connect方法中的参数为一个String类型的url即网页的链接
                     * userAgent方法中的参数为手机浏览器的模拟器(不知道是不是,我感觉好像是)
                     * timeout即超时链接的时间
                     * 最后调用get方法,然后传给一个Document的对象doc来接收,该方法需要对异常做处理
                     */
                    Document doc = Jsoup.connect(url).userAgent("Mozilla/5.0 (Windows NT 10.0; WOW64) " +
                            "AppleWebKit/537.36 (KHTML, like G" +
                            "ecko) Chrome/53.0.2785.104 " +
                            "Safari/537.36 Core/1.53.3226.400").timeout(10000).get();
                    /**然后用doc调用jsoup包下的select方法,该方法中有一个String类型的cssQuery参数,怎样获取
                     * 这个参数,后面会讲,这里先用一个String类型的参数顶上,该方法返回的类型为Elements,是
                     * 在jsoup包下的一个类
                     */
                    Elements titleEls = doc.select(title);
                    Elements artistEls = doc.select(artist);
                    //这里我们遍历一下我们所获取的信息,然后通过bean类封装信息再把信息添加到集合中
                    for (int i = 0;i<titleEls.size();i++){
                        //实例化NetSongsResults
                        NetSongsResults netSongsResults = new NetSongsResults();
                        //getAllElements方法为获取该cssQuery下的所有标签(我网页学得不好,我也不知道是不是)
                        Elements title = titleEls.get(i).getAllElements();
                        //这里用netSongsResults调用set方法封装信息
                        netSongsResults.setMusicName(title.get(0).text());


                        Elements artist = artistEls.get(i).getAllElements();
                        netSongsResults.setArtist(artist.get(0).text());
                        //这里添加专辑名,随便起一个
                        netSongsResults.setAlbum("最新推荐");
                        //最后把netSongsResults添加到集合中
                        datalist.add(netSongsResults);
                    }
                    //判断如果数据源不为空的时候调用回调接口的Success方法,为空时调用Error方法
                        if (datalist != null){
                            mCallBack.Success(datalist);
                        } else {
                            mCallBack.Error(datalist);
                        }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }
    //这里我们定义一个回调接口,判断是否成功的获取到了datalist
    public interface CallBack{
        public void Success(ArrayList<NetSongsResults> datalist);
        public void Error(ArrayList<NetSongsResults> datalist);
    }
}

弄好了工具类之后,我们弄一个自定义适配器去为了让ListView显示数据,ListView中的每一项的布局为:

item_net_song_layout.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    >


    <TextView
        android:id="@+id/item_net_title"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:singleLine="true"
        android:layout_marginLeft="10dp"
        android:layout_marginTop="5dp"
        android:textSize="17sp"
        />


    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="10dp"
        android:orientation="horizontal"
        android:layout_marginLeft="10dp"
        android:layout_marginBottom="10dp"
        >


        <TextView
            android:id="@+id/item_net_artist"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:singleLine="true"
            android:text="未知艺术家"
            android:textSize="15sp" />


        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="  -  "
            android:textSize="20sp"
            />


        <TextView
            android:id="@+id/item_net_ablum"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:singleLine="true"
            android:text="未知专辑"
            android:textSize="15sp" />
    </LinearLayout>
</LinearLayout>

弄好了布局之后就开始写自定义适配器了

public class NetSongAdapter extends BaseAdapter {
    private Context context; //上下文
    private ArrayList<NetSongsResults> datalist; //数据源
    private LayoutInflater inflater; //布局填充器
    private NetSongsResults netSongsResults; 
    public NetSongAdapter(Context context, ArrayList<NetSongsResults> datalist) {
        this.context = context;
        this.datalist = datalist;
        this.inflater = LayoutInflater.from(context);
    }


    @Override
    public int getCount() {
        return datalist.size();
    }


    @Override
    public Object getItem(int i) {
        return datalist.get(i);
    }


    @Override
    public long getItemId(int i) {
        return i;
    }


    @Override
    public View getView(int position, View convertView, ViewGroup viewGroup) {
        ViewHolder holder = null;
        if (convertView == null){
            holder = new ViewHolder();
            convertView = inflater.inflate(R.layout.item_net_song_layout,null);
            holder.title = convertView.findViewById(R.id.item_net_title);
            holder.artist = convertView.findViewById(R.id.item_net_artist);
            holder.ablum = convertView.findViewById(R.id.item_net_ablum);
            convertView.setTag(holder);
        } else {
            holder = (ViewHolder) convertView.getTag();
        }

//实例化NetSongsResults对象,去接收datalist.get(position);
        netSongsResults = datalist.get(position);


        String artist = netSongsResults.getArtist();
        String ablum = netSongsResults.getAlbum();
        holder.title.setText(netSongsResults.getMusicName());
        if (!TextUtils.isEmpty(artist)){
            holder.artist.setText(artist);
        } else {
            holder.artist.setText("未知艺术家");
        }
        if (!TextUtils.isEmpty(ablum)){
            holder.ablum.setText(ablum);
        }else {
            holder.ablum.setText("未知专辑");
        }


        return convertView;
    }


    class ViewHolder{
        TextView title;
        TextView artist;
        TextView ablum;
    }
}

适配器也弄好了,我们就开始去写MainActivity了

public class MainActivity extends AppCompatActivity {
    private ListView net_song_listview;
    private static final String url = "http://music.baidu.com/search?key=%E8%96%9B%E4%B9%8B%E8%B0%A6";
    private ArrayList<NetSongsResults> datalist;
    private NetSongAdapter netSongAdapter;
    private Handler handler;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
    }


    private void initView() {
        net_song_listview = (ListView) findViewById(R.id.net_song_listview);


        handler = new Handler(){
            @Override
            public void handleMessage(Message msg) {
                switch (msg.what){
                    case Contents.ConnectSuccess:
                        netSongAdapter = new NetSongAdapter(MainActivity.this,datalist);
                        net_song_listview.setAdapter(netSongAdapter);
                        Toast.makeText(MainActivity.this,"更新完成...",Toast.LENGTH_SHORT).show();
                        break;
                    case Contents.ConnectFail:
                        //msg.what = (int) msg.obj;
                        Toast.makeText(MainActivity.this,"更新失败...",Toast.LENGTH_SHORT).show();
                        break;
                }
            }
        };
        datalist = new ArrayList<NetSongsResults>();

        JsoupUtils.getInstance().getMusic(url, "span.song-title", "span.author_list",
                datalist, new JsoupUtils.CallBack() {
            @Override
            public void Success(ArrayList<NetSongsResults> datalist) {
                if (datalist != null ){
                    handler.sendEmptyMessage(Contents.ConnectSuccess);
                }else {
                    return;
                }
            }


            @Override
            public void Error(ArrayList<NetSongsResults> datalist) {
                if (datalist == null){
                    handler.sendEmptyMessage(Contents.ConnectFail);
                }
            }
        });
    }
}


这样就把获取网络歌曲信息的功能写完了,最后需要在配置文件AndroidManifest.xml中添加网络权限

<uses-permission android:name="android.permission.INTERNET" />


实际图是这样的:

Android使用jsoup解析音乐网站获取歌名与歌手名显示在ListView上

之前也有提到在Elements中的select方法的参数怎么去用,这里我也是参考前辈的用法粗略的说一下:

首先打开一个网址:https://try.jsoup.org/

打开网页后点击Fetch Url,会出现下面的窗口:

Android使用jsoup解析音乐网站获取歌名与歌手名显示在ListView上

这时候就会出现这样:Android使用jsoup解析音乐网站获取歌名与歌手名显示在ListView上

这些都是网页的解析出来的数据,然后再做以下操作:

Android使用jsoup解析音乐网站获取歌名与歌手名显示在ListView上

这样我们就讲完了,如果我讲的有什么地方不好的还请帮忙指出,因为我也是个初学者,学得也不太好,而且也是第一次写博客,希望大家多多支持!Android使用jsoup解析音乐网站获取歌名与歌手名显示在ListView上Android使用jsoup解析音乐网站获取歌名与歌手名显示在ListView上Android使用jsoup解析音乐网站获取歌名与歌手名显示在ListView上