网易云音乐API 分析

这几天一直在做一个仿QQ音乐的APP,但是苦于资金问题,一直没能解决服务器问题,所以打算使用第三方的服务。我这里的第三方就是网易云。

在此之前,我有分析过多家的api,大部分都不太好实现。其技术难点就在于获取音乐文件的请求都已经使用了tcp进行实现,获取的难度太大。不过有一家除外,那就是网易云。

我们这里使用重放攻击来实现获取服务器信息。打开我们的charles(如果你还没有下载过,请参考我的这篇博客:http://blog.csdn.net/u013022222/article/details/51693702

打开云音乐,第一个看到的请求就是这个
这里写图片描述

我们看下请求raw数据:
这里写图片描述
一次post请求,夹带了一个看起来什么都不像的字符串,显然是以某种方式encode过的。在cookie里,有一段appver的KV对。我尝试过各种组合,发现我们的请求里只需要夹带这个cookie就可以了。

我们开始尝试重放这次请求,为了方便我们使用的Okhttp这个库:

        OkHttpClient okHttpClient = new OkHttpClient();
        Request.Builder builder = new Request.Builder();

        String url = "http://music.163.com/eapi/batch";


        FormEncodingBuilder formEncodingBuilder = new FormEncodingBuilder();
        formEncodingBuilder.add("params", "0BD8BB39A78692F1744DEFF63EBC30F7889FA0D28FD18C56783C7BF3AADA4C516E269DCEF72717031B0D0797563D21D74A80931032E90A0DBF772B7B86DAB7B29C47227066BA6859EF81B2BDC94960501592EFDBED2FA4BB612DD34C3BE69C1CB997189A2D14BE23FACD2D81694F87D7D86DD3F48F213C035A89EDEE2F6336478BEBA964633B3DB2A074EA2662FE8AEC18A167403EA0D465ED99F6E0BF1B58D64E2F6FAB87BFB382901FB3F8D753ABABE5361DD03E8767F3CC5BE299EDCBF8CEA82126579A7E11CD9A6B7A95AEB41CEC237356031206C2C94443360BB430F44D4CE1F78FE98FDF4468B40977A33CD3A7AD9A9F926C5E1B3979139277DBCDF27E7EB4BFC0C4996CD069835883475527C7D296034459225E90FC0FD45F259EDAD79318B200CCC01B51E4571EFD93F7E7EFE09D1169A86936C7C3D1E0EAAFE6955D2A72808C6F340B4388E57F4443C22DCB267E6BA157E3256F2924B9A2DD0B1F4C001E848DC9F85F05DE82FCCA50763549329EF9DF1BC9746B9CFB7308D72159C5A5DC242B76960F7E62827FD52B8F4BCF7A667EBDAD93E5D34CB68D92ECBCD7FEE9265DD359457ED508F38B088041E5BBFDB949F891FA490B48B24C2C754762F31DC4C0F0C8E3930D08A628D82D10C6CADDEA0BBDF8D9FF405C9FE9B2E5622BD99757F50109BF2BBE0B6804606EB5EF23E3D772D023013244905739680AC5801E039D02D768DDB47BE085BE698DFA91C29B13F34AFEC3DA8E69251F8EB21D1A11B85F89B6383089FEF4713C1C21972D09E2433FEDADBAB3B6ED239935E06E76AACA3A66B3F11E51EFD0F5AD0CE6A32783");

        RequestBody requestBody = formEncodingBuilder.build();

        builder.addHeader("Accept", "*/*");
        builder.addHeader("Accept-Encoding", "gzip,deflate,sdch");
        builder.addHeader("Accept-Language", "zh-CN,zh;q=0.8,gl;q=0.6,zh-TW;q=0.4");
        builder.addHeader("Connection", "keep-alive");
        builder.addHeader("Host", "music.163.com");
        builder.addHeader("Referer", "http://music.163.com/search/");

        builder.addHeader("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.152 Safari/537.36");
        builder.addHeader("Cookie", "appver=1.5.2");

        builder.post(requestBody);
        builder.url(url);

        Call call = okHttpClient.newCall(builder.build());
        Response response = call.execute();

        System.out.println(response.body().string());

运行结果如下:
这里写图片描述
哇,是一堆乱码,不过既然数据这么大,是服务器报错的可能还是很小的,我们在看看response的信息吧:
这里写图片描述

天,真的太简单了,返回的数据只是gzip压缩的而已,我们解压一下就可以了:

  OkHttpClient okHttpClient = new OkHttpClient();
        Request.Builder builder = new Request.Builder();

        String url = "http://music.163.com/eapi/batch";


        FormEncodingBuilder formEncodingBuilder = new FormEncodingBuilder();
        formEncodingBuilder.add("params", "0BD8BB39A78692F1744DEFF63EBC30F7889FA0D28FD18C56783C7BF3AADA4C516E269DCEF72717031B0D0797563D21D74A80931032E90A0DBF772B7B86DAB7B29C47227066BA6859EF81B2BDC94960501592EFDBED2FA4BB612DD34C3BE69C1CB997189A2D14BE23FACD2D81694F87D7D86DD3F48F213C035A89EDEE2F6336478BEBA964633B3DB2A074EA2662FE8AEC18A167403EA0D465ED99F6E0BF1B58D64E2F6FAB87BFB382901FB3F8D753ABABE5361DD03E8767F3CC5BE299EDCBF8CEA82126579A7E11CD9A6B7A95AEB41CEC237356031206C2C94443360BB430F44D4CE1F78FE98FDF4468B40977A33CD3A7AD9A9F926C5E1B3979139277DBCDF27E7EB4BFC0C4996CD069835883475527C7D296034459225E90FC0FD45F259EDAD79318B200CCC01B51E4571EFD93F7E7EFE09D1169A86936C7C3D1E0EAAFE6955D2A72808C6F340B4388E57F4443C22DCB267E6BA157E3256F2924B9A2DD0B1F4C001E848DC9F85F05DE82FCCA50763549329EF9DF1BC9746B9CFB7308D72159C5A5DC242B76960F7E62827FD52B8F4BCF7A667EBDAD93E5D34CB68D92ECBCD7FEE9265DD359457ED508F38B088041E5BBFDB949F891FA490B48B24C2C754762F31DC4C0F0C8E3930D08A628D82D10C6CADDEA0BBDF8D9FF405C9FE9B2E5622BD99757F50109BF2BBE0B6804606EB5EF23E3D772D023013244905739680AC5801E039D02D768DDB47BE085BE698DFA91C29B13F34AFEC3DA8E69251F8EB21D1A11B85F89B6383089FEF4713C1C21972D09E2433FEDADBAB3B6ED239935E06E76AACA3A66B3F11E51EFD0F5AD0CE6A32783");

        RequestBody requestBody = formEncodingBuilder.build();

        builder.addHeader("Accept", "*/*");
        builder.addHeader("Accept-Encoding", "gzip,deflate,sdch");
        builder.addHeader("Accept-Language", "zh-CN,zh;q=0.8,gl;q=0.6,zh-TW;q=0.4");
        builder.addHeader("Connection", "keep-alive");
        builder.addHeader("Host", "music.163.com");
        builder.addHeader("Referer", "http://music.163.com/search/");

        builder.addHeader("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.152 Safari/537.36");
        builder.addHeader("Cookie", "appver=1.5.2");

        builder.post(requestBody);
        builder.url(url);

        Call call = okHttpClient.newCall(builder.build());
        Response response = call.execute();

        GZIPInputStream gzipInputStream = new GZIPInputStream(response.body().byteStream());
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        int length = -1;

        byte[] cache = new byte[1024];

        while ((length = gzipInputStream.read(cache)) != -1) {
            byteArrayOutputStream.write(cache, 0, length);
        }

        System.out.println(new String(byteArrayOutputStream.toByteArray()));

看下运行结果:
这里写图片描述
没毛病。

我们把返回的数据拷贝,贴进brackets,点击uri和云音乐界面进行对比:
这里写图片描述
这里写图片描述

这样依次找出json内容的含义。

最后我们可以找到新歌推荐的一些信息:
这里写图片描述

我们找到了歌曲uri和低质量音乐的信息。我们观察,可以发现上面Uri的后缀竟然和lMusic的id惊人的相似,我们不得不怀疑这个mp3地址是可以计算出来的。

我在分析一段时间后得出的结论就是,这个uri的确是计算出来的,方式如下:
1:前半段是固定字符串 http://m2.music.126.net/
2:中间部分是一段base64编码的字符串,别问为什么,很容易看出来。其内容以歌曲id对应的byte和key 异或之后得出的摘要
3:后段是歌曲id

实现方式如下:

        String input = "2946691177993133";
        String key = "3go8&$8*3*3h0k(2)2";
        byte[] keyBytes = key.getBytes();
        byte[] searchBytes = input.getBytes();

        for (int i = 0; i < searchBytes.length; ++i) {
            searchBytes[i] ^= keyBytes[i % keyBytes.length];
        }

        MessageDigest mdInst = MessageDigest.getInstance("MD5");
        mdInst.update(searchBytes);
        byte[] result = Base64.getEncoder().encode(mdInst.digest());
        String params = new String(result);
        params = params.replace("+", "-");
        params = params.replace("/", "_");

        System.out.println("http://m2.music.126.net/" + params + "/" + input + ".mp3");

run一遍,是不是已经成功了呢? 之后的博文我会陆续讲解如何使用查询api,敬请期待!

基于Spark进行网易云音乐数据分析的步骤如下: 1. 数据获取:从网易云音乐API中获取数据,或者从公开数据集中获取数据。 2. 数据清洗:对数据进行清洗,包括去重、缺失值处理、异常值处理等。 3. 数据预处理:对数据进行预处理,包括特征提取、特征选择、数据转换等。 4. 数据分析:使用Spark的分布式计算能力进行数据分析,包括统计分析、机器学习等。 5. 结果可视化:将分析结果进行可视化展示,包括图表、报表等。 以下是一个基于Spark进行网易云音乐数据分析的例子: ```scala // 导入Spark SQL和Spark MLlib库 import org.apache.spark.sql.SparkSession import org.apache.spark.ml.feature.{HashingTF, IDF, Tokenizer} import org.apache.spark.ml.clustering.KMeans // 创建SparkSession val spark = SparkSession.builder.appName("NetEaseMusicAnalysis").getOrCreate() // 读取数据 val data = spark.read.format("csv").option("header", "true").load("netease_music_data.csv") // 数据清洗 val cleanedData = data.dropDuplicates().na.drop() // 数据预处理 val tokenizer = new Tokenizer().setInputCol("song_name").setOutputCol("words") val wordsData = tokenizer.transform(cleanedData) val hashingTF = new HashingTF().setInputCol("words").setOutputCol("rawFeatures").setNumFeatures(10000) val featurizedData = hashingTF.transform(wordsData) val idf = new IDF().setInputCol("rawFeatures").setOutputCol("features") val idfModel = idf.fit(featurizedData) val rescaledData = idfModel.transform(featurizedData) // 数据分析 val kmeans = new KMeans().setK(10).setSeed(1L) val model = kmeans.fit(rescaledData.select("features")) val predictions = model.transform(rescaledData) // 结果可视化 predictions.groupBy("prediction").count().show() ``` 该例子使用Spark对网易云音乐的歌曲名称进行聚类分析分析结果展示了每个聚类中歌曲数量的统计信息。
评论 16
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值