import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import object.Album;
import object.Dicover;
import object.JsonObj.MusicJsonObj;
import object.Work;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * date : 2020/2/13 22:27
 * author : 老逼的电脑
 */
public class MainApp {
    public static void main(String[] args) throws IOException {
        MainApp mainApp = new MainApp();
        //获取所有大分类
        List<String> strings = mainApp.getCates();
        System.out.println("所有大分类" + strings.size());
        //获取所有大分类下的歌手分类
        List<String> discoverCatePaths = mainApp.getDiscoverCatePaths(strings);
        //获取歌手分类下的歌手链接
        List<String> dicoverPath = mainApp.getDicoverPath(discoverCatePaths);
        System.out.println("总共有" + dicoverPath.size() + "个歌手");
        //获取歌手信息
        for (String s : dicoverPath) {
            Dicover dicoverInfo = mainApp.getDicoverInfo(s);
            System.out.println("作者:" + dicoverInfo.getName());
            System.out.println("专辑数量:" + dicoverInfo.getAlbumList().size());
            System.out.println("热门单曲:" + dicoverInfo.getHotWorkList());
        }
    }


    private String index = "https://music.163.com";
    private String path = "/discover/artist";
    private final String musicPath = "http://music.163.com/song/media/outer/url?id={id}.mp3";

    /**
     * 获取所有分类信息
     *
     * @return
     * @throws IOException
     */
    public List<String> getCates() throws IOException {
        Elements doc = Jsoup.connect(index + path).get().getElementsByClass("cat-flag");
        return doc.stream()
                .filter(element -> element.attr("href")
                        .startsWith("/discover/artist/cat?"))
                .map(element -> index + element.attr("href"))
                .collect(Collectors.toList());
    }

    /**
     * 获取歌手分类下的链接
     */
    public List<String> getDiscoverCatePaths(List<String> cates) throws IOException {
        List<String> strings = new ArrayList<>();
        for (String cate : cates) {
            Document document = Jsoup.connect(cate).get();
            Element element = document.getElementById("initial-selector");
            Elements a = element.getElementsByTag("a");
            List<String> href = a.stream()
                    .map(element1 -> index + (element1.attr("href")
                            .replace("&amp;", "&")))
                    .filter(s -> !s.endsWith("=-1"))
                    .collect(Collectors.toList());
            strings.addAll(href);
        }
        return strings;
    }

    /**
     * 获取歌手的链接
     */
    public List<String> getDicoverPath(List<String> dicoverCatePaths) throws IOException {
        List<String> dicoverPaths = new ArrayList<>();
        for (String dicoverCatePath : dicoverCatePaths) {
            Element element = Jsoup.connect(dicoverCatePath).get().getElementById("m-artist-box");
            Elements a = element.getElementsByTag("a");
            List<String> href = a.stream().map(element1 -> index + element1.attr("href")).collect(Collectors.toList());
            //TODO 需要对链接进行去重复和排查
            dicoverPaths.addAll(href);
        }

        return dicoverPaths.stream().filter(s -> !s.contains(" ")).filter(s -> !s.contains("user")).collect(Collectors.toList());
    }

    /**
     * 获取歌手信息
     */
    public Dicover getDicoverInfo(String dicoverPath) throws IOException {
        Document document = Jsoup.connect(dicoverPath).get();
        //获取作者名字
        String dicoverName = document.getElementById("artist-name").text();
        //获取作者头像
        Elements select1 = document.getElementsByTag("img");
        String avatar = select1.get(0).attr("src");
        //获取热门单曲
        String json = document.getElementById("song-list-pre-data").text();
        List<MusicJsonObj> musicJsonObjs = parseMucsicList(json);
        List<String> hotmusic = musicJsonObjs.stream().map(musicJsonObj -> musicJsonObj.getName()).collect(Collectors.toList());


        //获取作者介绍
        Document doc = Jsoup.connect(dicoverPath.replace("artist", "artist/desc")).get();
        String introduction = doc.getElementsByClass("n-artdesc").html();
        Dicover dicover = new Dicover(dicoverName, avatar, null, introduction, hotmusic);

        //获取作者专辑列表

        String albumPath = document.getElementById("m_tabs").child(1).select("a").attr("href");
        List<Album> albums = getAlbums(index + albumPath);


        dicover.setAlbumList(albums);

        return dicover;
    }

    /**
     * 解析 json
     *
     * @return List<MusicJsonObj>
     */
    private List<MusicJsonObj> parseMucsicList(String json) {
        Gson gson = new Gson();
        List<MusicJsonObj> hotMusicJsons = gson.fromJson(json, new TypeToken<ArrayList<MusicJsonObj>>() {
        }.getType());
        return hotMusicJsons;
    }

    private String parseMusicTime(int time) {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("mm:ss");
        return simpleDateFormat.format(new Date(time));
    }

    public List<Album> getAlbums(String album) throws IOException {
        List<Album> albumList = new ArrayList<>();

        Document albumDoc = Jsoup.connect(album).get();


        Element maxPage;
        do {
            Elements pages = albumDoc.getElementsByClass("u-page").select("a");

            Elements liList;
            try {
                Element elementById = albumDoc.getElementById("m-song-module");

                liList = elementById.getElementsByTag("li");
            } catch (NullPointerException e) {
                //如果没有专辑 跳出循环
                break;
            }

            //获取所有专辑
            for (Element element : liList) {
                String albumName = element.child(0).attr("title");
                String date = element.child(2).child(0).text();
                //获取专辑下的歌曲
                String albumPath = element.child(0).child(1).attr("href");
                Document albumDetail = Jsoup.connect(index + albumPath).get();

                List<MusicJsonObj> musicJsonObjs1 = parseMucsicList(albumDetail.getElementById("song-list-pre-data").text());
                List<Work> workList = musicJsonObjs1.stream().map(musicJsonObj ->
                        new Work(musicJsonObj.getName(),
                                parseMusicTime(musicJsonObj.getDuration()),
                                musicPath.replace("{id}", musicJsonObj.getPrivilege().getId() + ""))
                ).collect(Collectors.toList());

                albumList.add(new Album(albumName, date, workList));
            }

            //判定是不是最后一页 是的话跳出循环
            try {
                maxPage = pages.get(pages.size() - 1);
            } catch (ArrayIndexOutOfBoundsException | NullPointerException n) {
                break;
            }


            if (!maxPage.attr("href").equals("javascript:void(0)")) {
                albumDoc = Jsoup.connect(index + maxPage.attr("href")).get();
            } else {
                break;
            }


        } while (!maxPage.attr("href").equals("javascript:void(0)"));

        return albumList;
    }


}
最近下载更多
wahahaCode  LV1 2023年1月5日
好的好的  LV8 2022年7月7日
crosa_Don  LV18 2022年6月14日
dhvdsgfggfjhfggfyu  LV4 2022年1月10日
whmr_soft  LV10 2021年9月27日
李疾风  LV1 2021年7月7日
许元宵  LV1 2021年5月17日
3090362054aaa  LV1 2021年2月1日
1232136456  LV1 2020年12月7日
lc1234560  LV1 2020年10月17日
最近浏览更多
panqiuhong  LV7 2月24日
雨中纸鹤  LV1 2023年12月6日
内心向阳  LV4 2023年11月8日
tyyeng  LV18 2023年10月10日
科技家  LV2 2023年3月15日
a1017514773  LV6 2023年3月14日
wahahaCode  LV1 2023年1月5日
wawayv  LV2 2022年12月12日
qwertyuiopzxc  LV1 2022年10月14日
好的好的  LV8 2022年7月7日
顶部 客服 微信二维码 底部
>扫描二维码关注最代码为好友扫描二维码关注最代码为好友