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日
好的好的  LV9 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日
最近浏览更多
2946489117  LV1 6月11日
TY0165  LV20 2024年6月24日
微信网友_7005760998215680  LV6 2024年6月4日
panqiuhong  LV7 2024年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日
顶部 客服 微信二维码 底部
>扫描二维码关注最代码为好友扫描二维码关注最代码为好友