js逆向爬取某音乐网站某歌手的歌曲

js逆向爬取某音乐网站某歌手的歌曲

  • 一、分析网站
    • 1、案例介绍
    • 2、寻找列表页Ajax入口
      • (1)页面展示图。
      • (2)寻找部分歌曲信息Ajax的token。
      • (3)寻找歌曲链接
      • (4)获取歌曲名称和id信息
    • 3、寻找网页数据的加密逻辑
      • (1)寻找歌曲地址出处。
      • (2)查找表单数据中的关键字
      • (3)建立生成方法的js文件
      • (4)编辑“生成构造歌曲地址的表单数据方法”的代码
  • 二、开始爬取工作
    • 1、构建歌曲地址
    • 2、修改JS文件中的参数
    • 3、成功获得歌曲链接的地址
  • 三、保存并总结

一、分析网站

1、案例介绍

  • 爬虫学习已经结束了,再继续练习巩固。这一次拿某音乐网站某歌星的歌曲为例,进行批量爬取。
  • 这里的前端javaScript带有变量名混淆,也带有字符串混淆,还带有对象键名替换等技术,所以爬取起来,要花费一定的时间去分析并理清里面的逻辑关系。
  • 这次的练习,目的很简单,思路也不麻烦,就是找到歌曲的url地址和歌曲名称,再爬取、保存。

2、寻找列表页Ajax入口

(1)页面展示图。

在这里插入图片描述

这里还是用右击“检查”的形式,对上面页面进行分析。虽然在“元素”这一栏能找到歌曲的链接及名字,但这次,源代码里面是找不到的,那就意味着用requests爬取不到需要的信息。

(2)寻找部分歌曲信息Ajax的token。

  • 接着打开“网络”——“Fetch/XHR”,刷新之后,开始查找列表,出现很多含有“token=”的列表项,按照经验,找到“web?csrf_token=”,点击“预览”,找到想要的信息列表。如图。
    在这里插入图片描述
  • 在爬取类似歌曲信息的时候,需要注意的一点就是要关注这些列表中的id信息。
  • 在“标头”栏,找到请求头“https://music.YouKnowde.com/weapi/cloudsearch/get/web?csrf_token=”,这个地址也要写入程序里面,而且看到下面的请求方法是POST方式。
  • 再打开“载荷”栏,查看表单数据。如图。
    在这里插入图片描述
    上面表单数据的格式是通过加密后产生的,可以查看md5.cn网站,比较得出是哪一种加密方式。
  • 先用以上信息,写一段代码,获取一部分信息,再做进一步的分析。
import requests


class Music_Data(object):
    def __init__(self):
        super().__init__()
        self.url = "https://music.YouKnowde.com/weapi/cloudsearch/get/web?csrf_token="
        self.wangyi_url = 'https://music.YouKnowde.com/weapi/song/enhance/player/url/v1?csrf_token='
        self.headers = {
            'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36',
            'origin': 'https://music.YouKnowde.com',
            'referer': 'https://music.YouKnowde.com/search/'
        }

        self.data = {
            "params": "VcB5Z4BiekLvHcWYMKc78nXTiKKCn+6eAjm8yfLksGSJr9rPpDKZP8HPJG9BYL33uYq97UL2UDkQdhq6QoKm8d+bzvJstjrmn8PDCUwE6azkPUCIhiMnCE5sonqHw8D0OGvEk0N/v3PYGqcc/Cp4HvJmrQoS50BlcA8h7X7Djcal1ku2A03QrOqT4Zkai78O4c95I5rHDxecBZbi8pvA7jji9Gf7mPmOJ1ZqaLvtsbSg+CbtyFBUWvzfQqWXKejd8hgFePlM4i/yEWb6Ug5BQg==",
            "encSecKey": "c2dfcdf582d19c7ec069d8315befe647a0a91af398a44bb994cf69386977115df512627a4f7c4c82ec9a608fe0ea6de0e4063a4bea2a6af703615133b0b64e22adb20484dfa5db22b72866c0ab9529237cfdf9b4eaa8d67294c896de380658fa859167b67c73a35c5d65c97ba839d1a6d1feca697eedf6ef9b6bf2663fc561e3"
        }

    def get_data_index(self):
        resp = requests.post(url=self.url, data=self.data, headers=self.headers)
        print(resp.text)

    def run(self):
        self.get_data_index()


if __name__ == '__main__':
    music = Music_Data()
    music.run()
  • 上面代码,自然获取到了歌曲的一些信息代码。如图。
    在这里插入图片描述
    从上面获得结果看,刚才乱码形式的表单数据,可以不用理会。

(3)寻找歌曲链接

  • 点击“媒体”——点击播放,看到如下结果。
    在这里插入图片描述

  • 点击这条记录,再点击“标头”栏看到请求网址信息,复制到地址栏“转到”,就能听到歌曲播放。
    在这里插入图片描述

在这里插入图片描述
那么,刚才请求网址的链接,就是这首歌的播放地址。也就是说,这样就成功的找到一首歌的地址链接了。

  • 然后我们看到,请求网址的地址比较乱,无规则的字符掺杂其中,那它到底是怎么来的。

(4)获取歌曲名称和id信息

  • 还是在开发者工具界面,点击“网络”——“Fetch/XHR”——刷新网页并选择“web?csrf_token=”——预览,就看到字典格式的内容,用json中的方法loads改成字典格式,进一步获得歌曲名称和id信息。
    在这里插入图片描述
  • 改写程序中的get_data_index方法,由获取源代码,进一步改成获取歌曲名称和id的方法。
  • 代码如下:
    def get_data_index(self):
        resp = requests.post(url=self.url, data=self.data, headers=self.headers)
        # print(resp.text)
        # 此处根据web?csrf_token=链接汇总的预览栏,找到字典形式的信息,获取相应歌曲名
        dict_data = json.loads(resp.text)["result"]["songs"]
        # 而后遍历所有歌曲,获取name和id
        for data in dict_data:
            name = data["name"]
            id = data["id"]
            print(name, id)
    
    • 运行之后,成功获取到想要的信息。如图。
      在这里插入图片描述

3、寻找网页数据的加密逻辑

(1)寻找歌曲地址出处。

  • 在上面请求网址的地址代码中,复制一小段,然后搜索即得到两个结果。如图。
    在这里插入图片描述
    经过分析,点击第二个结果的链接,再点击预览,看到下面字典格式的信息里面,就有歌曲信息的链接。如图。
    在这里插入图片描述
    再继续点开上图所示的开发者工具中的“标头”,它里面的请求网址,就是产生这首歌曲地址的请求地址。而且是以POST的请求方式。如图。
    在这里插入图片描述
  • 再按以上方式,找到一首歌曲的地址。即:媒体——播放——选中,复制一段代码搜索——找到请求网址。然后,再点“载荷”一栏,得到表单数据,也是params和encSecKey两项,不过此时的字符串变了。也就是说,换了不同的歌曲,就更换了不同的表单数据
  • 显然,每次爬取歌曲,都要更换此处的表单数据,确实是挺麻烦的事。那么接下来,应该怎么做呢?
  • 答案就是,表单数据是网页中JavaScript代码产生的,咱们应该继续网页表单数据中params和encSecKey两项的生成机制。即,分析明白,网页中的这一加密逻辑。

(2)查找表单数据中的关键字

  • 通过如下方式,在源代码js逻辑代码中,寻找表单数据中的encSecKey的代码段。步骤如下图。
    在这里插入图片描述
    点开上面,会进入源代码里面,继续搜索“encSecKey”,会找到下图的地方,这里就是表单数据生成的代码块。
    在这里插入图片描述

显然,上面代码中使用了字符串混淆和对象键名替换的技术。然后我们分析发现,params和encSecKey两个键对应的值里面有一个bMr1x,而bMr1x又在上面被var定义好了。再看bMr1x的定义,里面又用到了window.asrsea这个方法,接着继续搜索关键字window.asrsea,看看别处有没有定义。搜索完成,就两个结果,除了当前应用的这个地方,上面不远处,就是定义的地方。如图。
在这里插入图片描述

  • 在这里我们发现,d就是上面定义的函数(方法),在这里给d函数断点,再播放歌曲。因为有断点,所以歌曲没有播放,马上暂停了,得到一系列参数。如图。
    在这里插入图片描述
    我们看到,上面代码中,又应用了变量名混淆的技术,变量名或函数名全部是a、b、c这样的字眼。因为我们需要的是,生成表单数据的功能,此时只要把这部分代码拿出来,形成一个js文件,就能为我所用。所以,我们复制实现这个功能的这一整个函数即可,如图。
    在这里插入图片描述在这里插入代码片段。

(3)建立生成方法的js文件

  • 在PyCharm平台,新建一个wyy.js文件,把上面复制的JavaScript函数代码,粘贴进来,再进行适当的增删,把它的功能重建。
!function() {
    function a(a) {
        var d, e, b = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789", c = "";
        for (d = 0; a > d; d += 1)
            e = Math.random() * b.length,
            e = Math.floor(e),
            c += b.charAt(e);
        return c
    }
    function b(a, b) {
        var c = CryptoJS.enc.Utf8.parse(b)
          , d = CryptoJS.enc.Utf8.parse("0102030405060708")
          , e = CryptoJS.enc.Utf8.parse(a)
          , f = CryptoJS.AES.encrypt(e, c, {
            iv: d,
            mode: CryptoJS.mode.CBC
        });
        return f.toString()
    }
    function c(a, b, c) {
        var d, e;
        return setMaxDigits(131),
        d = new RSAKeyPair(b,"",c),
        e = encryptedString(d, a)
    }
    function d(d, e, f, g) {
        var h = {}
          , i = a(16);
        return h.encText = b(d, g),
        h.encText = b(h.encText, i),
        h.encSecKey = c(i, e, f),
        h
    }
    function e(a, b, d, e) {
        var f = {};
        return f.encText = c(a + e, b, d),
        f
    }
    asrsea = d
}();
  • 分析上面可知,里面定义了a、b、c、d四个函数,然后运行完之后,得到四个结果。如上图右侧的红色部分。继续分析可以看出,经过混淆后,代码里面的下面这段,其中bMr1x定义完成的功能,就是上面js程序的d函数调用完成的功能。

    var bMr1x = window.asrsea(JSON.stringify(i0x), bsg8Y(["流泪", "强"]), bsg8Y(TH5M.md), bsg8Y(["爱心", "女孩", "惊恐", "大笑"]));
                e0x.data = j0x.cr0x({
                    params: bMr1x.encText,
                    encSecKey: bMr1x.encSecKey
    
  • 这样,在同一个wyy.js文件里面,再写一个函数。因为上述代码里面,掺入了变量名混淆、对象键名替换等技术,仔细分析,就是一个函数调用函数,再依次返回数据(得到返回值)的过程。由此可以建立如下代码:

    function start() {
        d:"{\"id\":\"190072\",\"c\":\"[{\\\"id\\\":\\\"190072\\\"}]\",\"csrf_token\":\"\"}"
        e:"010001"
        f:"00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7b725152b3ab17a876aea8a5aa76d2e417629ec4ee341f56135fccf695280104e0312ecbda92557c93870114af6c9d05c4f7f0c3685b7a46bee255932575cce10b424d813cfe4875d3e82047b97ddef52741d546b8e289dc6935b3ece0462db0a22b8e7"
        g:"0CoJUm6Qyw8W8jud"
        var bMr1x = asrsea(JSON.stringify(d),e,f,g)
        return bMr1x
    }
    
  • 上面两段代码,是从网页源代码中剥离出来,放到wyy.js里面,对函数内部运作方法稍加分析之后,重新整理合适的代码,整个wyy.js代码改成如下形式:

!function() {
    function a(a) {
        var d, e, b = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789", c = "";
        for (d = 0; a > d; d += 1)
            e = Math.random() * b.length,
            e = Math.floor(e),
            c += b.charAt(e);
        return c
    }
    function b(a, b) {
        var c = CryptoJS.enc.Utf8.parse(b)
          , d = CryptoJS.enc.Utf8.parse("0102030405060708")
          , e = CryptoJS.enc.Utf8.parse(a)
          , f = CryptoJS.AES.encrypt(e, c, {
            iv: d,
            mode: CryptoJS.mode.CBC
        });
        return f.toString()
    }
    function c(a, b, c) {
        var d, e;
        return setMaxDigits(131),
        d = new RSAKeyPair(b,"",c),
        e = encryptedString(d, a)
    }
    function d(d, e, f, g) {
        var h = {}
          , i = a(16);
        return h.encText = b(d, g),
        h.encText = b(h.encText, i),
        h.encSecKey = c(i, e, f),
        h
    }
    function e(a, b, d, e) {
        var f = {};
        return f.encText = c(a + e, b, d),
        f
    }
    asrsea = d
}();


function start() {
    var d = {"ids":"[1894007406]","level":"standard","encodeType":"aac","csrf_token":""}
    var e = "010001"
    var f = "00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7b725152b3ab17a876aea8a5aa76d2e417629ec4ee341f56135fccf695280104e0312ecbda92557c93870114af6c9d05c4f7f0c3685b7a46bee255932575cce10b424d813cfe4875d3e82047b97ddef52741d546b8e289dc6935b3ece0462db0a22b8e7"
    var g = "0CoJUm6Qyw8W8jud"
    var bMr1x = asrsea(JSON.stringify(d),e,f,g)
    return bMr1x
}

(4)编辑“生成构造歌曲地址的表单数据方法”的代码

  • 上面得到了歌曲名称和id,下面就构建歌曲地址。在程序中,重新定义一个函数get_music_url_index,然后运行。
    在这里插入图片描述
  • 上面的代码运行后,得到错误。这是因为前面的wyy.js中有一个函数变量,没有写入wyy.js程序中,还有下面的setMaxDigits等函数,如图黄色方框内的方法。
    在这里插入图片描述
  • 因此索性,把CryptoJS开头定义的代码,一直复制到与前面函数交界的地方。这里有个技巧,选择就容易许多。就是在源代码中的下方,有一队大括号{},点击一下,一个函数的代码就收缩起来,此处选择三个方法CryptoJS、RSAKeyPair和encryptedString,正好和前面d函数所在的函数紧挨着。选择好之后,复制粘贴到wyy.js的开端。整个代码如下:
    var CryptoJS=CryptoJS||function(u,p){var d={},l=d.lib={},s=function(){},t=l.Base={extend:function(a){s.prototype=this;var c=new s;a&&c.mixIn(a);c.hasOwnProperty("init")||(c.init=function(){c.$super.init.apply(this,arguments)});c.init.prototype=c;c.$super=this;return c},create:function(){var a=this.extend();a.init.apply(a,arguments);return a},init:function(){},mixIn:function(a){for(var c in a)a.hasOwnProperty(c)&&(this[c]=a[c]);a.hasOwnProperty("toString")&&(this.toString=a.toString)},clone:function(){return this.init.prototype.extend(this)}},r=l.WordArray=t.extend({init:function(a,c){a=this.words=a||[];this.sigBytes=c!=p?c:4*a.length},toString:function(a){return(a||v).stringify(this)},concat:function(a){var c=this.words,e=a.words,j=this.sigBytes;a=a.sigBytes;this.clamp();if(j%4)for(var k=0;k<a;k++)c[j+k>>>2]|=(e[k>>>2]>>>24-8*(k%4)&255)<<24-8*((j+k)%4);else if(65535<e.length)for(k=0;k<a;k+=4)c[j+k>>>2]=e[k>>>2];else c.push.apply(c,e);this.sigBytes+=a;return this},clamp:function(){var a=this.words,c=this.sigBytes;a[c>>>2]&=4294967295<<32-8*(c%4);a.length=u.ceil(c/4)},clone:function(){var a=t.clone.call(this);a.words=this.words.slice(0);return a},random:function(a){for(var c=[],e=0;e<a;e+=4)c.push(4294967296*u.random()|0);return new r.init(c,a)}}),w=d.enc={},v=w.Hex={stringify:function(a){var c=a.words;a=a.sigBytes;for(var e=[],j=0;j<a;j++){var k=c[j>>>2]>>>24-8*(j%4)&255;e.push((k>>>4).toString(16));e.push((k&15).toString(16))}return e.join("")},parse:function(a){for(var c=a.length,e=[],j=0;j<c;j+=2)e[j>>>3]|=parseInt(a.substr(j,2),16)<<24-4*(j%8);return new r.init(e,c/2)}},b=w.Latin1={stringify:function(a){var c=a.words;a=a.sigBytes;for(var e=[],j=0;j<a;j++)e.push(String.fromCharCode(c[j>>>2]>>>24-8*(j%4)&255));return e.join("")},parse:function(a){for(var c=a.length,e=[],j=0;j<c;j++)e[j>>>2]|=(a.charCodeAt(j)&255)<<24-8*(j%4);return new r.init(e,c)}},x=w.Utf8={stringify:function(a){try{return decodeURIComponent(escape(b.stringify(a)))}catch(c){throw Error("Malformed UTF-8 data")}},parse:function(a){return b.parse(unescape(encodeURIComponent(a)))}},q=l.BufferedBlockAlgorithm=t.extend({reset:function(){this.i0x=new r.init;this.yE7x=0},Ap8h:function(a){"string"==typeof a&&(a=x.parse(a));this.i0x.concat(a);this.yE7x+=a.sigBytes},mD4H:function(a){var c=this.i0x,e=c.words,j=c.sigBytes,k=this.blockSize,b=j/(4*k),b=a?u.ceil(b):u.max((b|0)-this.UZ5e,0);a=b*k;j=u.min(4*a,j);if(a){for(var q=0;q<a;q+=k)this.tt6n(e,q);q=e.splice(0,a);c.sigBytes-=j}return new r.init(q,j)},clone:function(){var a=t.clone.call(this);a.i0x=this.i0x.clone();return a},UZ5e:0});l.Hasher=q.extend({cfg:t.extend(),init:function(a){this.cfg=this.cfg.extend(a);this.reset()},reset:function(){q.reset.call(this);this.mk4o()},update:function(a){this.Ap8h(a);this.mD4H();return this},finalize:function(a){a&&this.Ap8h(a);return this.nZ4d()},blockSize:16,mO4S:function(a){return function(b,e){return(new a.init(e)).finalize(b)}},yD7w:function(a){return function(b,e){return(new n.HMAC.init(a,e)).finalize(b)}}});var n=d.algo={};return d}(Math);(function(){var u=CryptoJS,p=u.lib.WordArray;u.enc.Base64={stringify:function(d){var l=d.words,p=d.sigBytes,t=this.bD0x;d.clamp();d=[];for(var r=0;r<p;r+=3)for(var w=(l[r>>>2]>>>24-8*(r%4)&255)<<16|(l[r+1>>>2]>>>24-8*((r+1)%4)&255)<<8|l[r+2>>>2]>>>24-8*((r+2)%4)&255,v=0;4>v&&r+.75*v<p;v++)d.push(t.charAt(w>>>6*(3-v)&63));if(l=t.charAt(64))for(;d.length%4;)d.push(l);return d.join("")},parse:function(d){var l=d.length,s=this.bD0x,t=s.charAt(64);t&&(t=d.indexOf(t),-1!=t&&(l=t));for(var t=[],r=0,w=0;w<l;w++)if(w%4){var v=s.indexOf(d.charAt(w-1))<<2*(w%4),b=s.indexOf(d.charAt(w))>>>6-2*(w%4);t[r>>>2]|=(v|b)<<24-8*(r%4);r++}return p.create(t,r)},bD0x:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="}})();(function(u){function p(b,n,a,c,e,j,k){b=b+(n&a|~n&c)+e+k;return(b<<j|b>>>32-j)+n}function d(b,n,a,c,e,j,k){b=b+(n&c|a&~c)+e+k;return(b<<j|b>>>32-j)+n}function l(b,n,a,c,e,j,k){b=b+(n^a^c)+e+k;return(b<<j|b>>>32-j)+n}function s(b,n,a,c,e,j,k){b=b+(a^(n|~c))+e+k;return(b<<j|b>>>32-j)+n}for(var t=CryptoJS,r=t.lib,w=r.WordArray,v=r.Hasher,r=t.algo,b=[],x=0;64>x;x++)b[x]=4294967296*u.abs(u.sin(x+1))|0;r=r.MD5=v.extend({mk4o:function(){this.cT1x=new w.init([1732584193,4023233417,2562383102,271733878])},tt6n:function(q,n){for(var a=0;16>a;a++){var c=n+a,e=q[c];q[c]=(e<<8|e>>>24)&16711935|(e<<24|e>>>8)&4278255360}var a=this.cT1x.words,c=q[n+0],e=q[n+1],j=q[n+2],k=q[n+3],z=q[n+4],r=q[n+5],t=q[n+6],w=q[n+7],v=q[n+8],A=q[n+9],B=q[n+10],C=q[n+11],u=q[n+12],D=q[n+13],E=q[n+14],x=q[n+15],f=a[0],m=a[1],g=a[2],h=a[3],f=p(f,m,g,h,c,7,b[0]),h=p(h,f,m,g,e,12,b[1]),g=p(g,h,f,m,j,17,b[2]),m=p(m,g,h,f,k,22,b[3]),f=p(f,m,g,h,z,7,b[4]),h=p(h,f,m,g,r,12,b[5]),g=p(g,h,f,m,t,17,b[6]),m=p(m,g,h,f,w,22,b[7]),f=p(f,m,g,h,v,7,b[8]),h=p(h,f,m,g,A,12,b[9]),g=p(g,h,f,m,B,17,b[10]),m=p(m,g,h,f,C,22,b[11]),f=p(f,m,g,h,u,7,b[12]),h=p(h,f,m,g,D,12,b[13]),g=p(g,h,f,m,E,17,b[14]),m=p(m,g,h,f,x,22,b[15]),f=d(f,m,g,h,e,5,b[16]),h=d(h,f,m,g,t,9,b[17]),g=d(g,h,f,m,C,14,b[18]),m=d(m,g,h,f,c,20,b[19]),f=d(f,m,g,h,r,5,b[20]),h=d(h,f,m,g,B,9,b[21]),g=d(g,h,f,m,x,14,b[22]),m=d(m,g,h,f,z,20,b[23]),f=d(f,m,g,h,A,5,b[24]),h=d(h,f,m,g,E,9,b[25]),g=d(g,h,f,m,k,14,b[26]),m=d(m,g,h,f,v,20,b[27]),f=d(f,m,g,h,D,5,b[28]),h=d(h,f,m,g,j,9,b[29]),g=d(g,h,f,m,w,14,b[30]),m=d(m,g,h,f,u,20,b[31]),f=l(f,m,g,h,r,4,b[32]),h=l(h,f,m,g,v,11,b[33]),g=l(g,h,f,m,C,16,b[34]),m=l(m,g,h,f,E,23,b[35]),f=l(f,m,g,h,e,4,b[36]),h=l(h,f,m,g,z,11,b[37]),g=l(g,h,f,m,w,16,b[38]),m=l(m,g,h,f,B,23,b[39]),f=l(f,m,g,h,D,4,b[40]),h=l(h,f,m,g,c,11,b[41]),g=l(g,h,f,m,k,16,b[42]),m=l(m,g,h,f,t,23,b[43]),f=l(f,m,g,h,A,4,b[44]),h=l(h,f,m,g,u,11,b[45]),g=l(g,h,f,m,x,16,b[46]),m=l(m,g,h,f,j,23,b[47]),f=s(f,m,g,h,c,6,b[48]),h=s(h,f,m,g,w,10,b[49]),g=s(g,h,f,m,E,15,b[50]),m=s(m,g,h,f,r,21,b[51]),f=s(f,m,g,h,u,6,b[52]),h=s(h,f,m,g,k,10,b[53]),g=s(g,h,f,m,B,15,b[54]),m=s(m,g,h,f,e,21,b[55]),f=s(f,m,g,h,v,6,b[56]),h=s(h,f,m,g,x,10,b[57]),g=s(g,h,f,m,t,15,b[58]),m=s(m,g,h,f,D,21,b[59]),f=s(f,m,g,h,z,6,b[60]),h=s(h,f,m,g,C,10,b[61]),g=s(g,h,f,m,j,15,b[62]),m=s(m,g,h,f,A,21,b[63]);a[0]=a[0]+f|0;a[1]=a[1]+m|0;a[2]=a[2]+g|0;a[3]=a[3]+h|0},nZ4d:function(){var b=this.i0x,n=b.words,a=8*this.yE7x,c=8*b.sigBytes;n[c>>>5]|=128<<24-c%32;var e=u.floor(a/4294967296);n[(c+64>>>9<<4)+15]=(e<<8|e>>>24)&16711935|(e<<24|e>>>8)&4278255360;n[(c+64>>>9<<4)+14]=(a<<8|a>>>24)&16711935|(a<<24|a>>>8)&4278255360;b.sigBytes=4*(n.length+1);this.mD4H();b=this.cT1x;n=b.words;for(a=0;4>a;a++)c=n[a],n[a]=(c<<8|c>>>24)&16711935|(c<<24|c>>>8)&4278255360;return b},clone:function(){var b=v.clone.call(this);b.cT1x=this.cT1x.clone();return b}});t.MD5=v.mO4S(r);t.HmacMD5=v.yD7w(r)})(Math);(function(){var u=CryptoJS,p=u.lib,d=p.Base,l=p.WordArray,p=u.algo,s=p.EvpKDF=d.extend({cfg:d.extend({keySize:4,hasher:p.MD5,iterations:1}),init:function(d){this.cfg=this.cfg.extend(d)},compute:function(d,r){for(var p=this.cfg,s=p.hasher.create(),b=l.create(),u=b.words,q=p.keySize,p=p.iterations;u.length<q;){n&&s.update(n);var n=s.update(d).finalize(r);s.reset();for(var a=1;a<p;a++)n=s.finalize(n),s.reset();b.concat(n)}b.sigBytes=4*q;return b}});u.EvpKDF=function(d,l,p){return s.create(p).compute(d,l)}})();CryptoJS.lib.Cipher||function(u){var p=CryptoJS,d=p.lib,l=d.Base,s=d.WordArray,t=d.BufferedBlockAlgorithm,r=p.enc.Base64,w=p.algo.EvpKDF,v=d.Cipher=t.extend({cfg:l.extend(),createEncryptor:function(e,a){return this.create(this.If2x,e,a)},createDecryptor:function(e,a){return this.create(this.brx8p,e,a)},init:function(e,a,b){this.cfg=this.cfg.extend(b);this.UA5F=e;this.J0x=a;this.reset()},reset:function(){t.reset.call(this);this.mk4o()},process:function(e){this.Ap8h(e);return this.mD4H()},finalize:function(e){e&&this.Ap8h(e);return this.nZ4d()},keySize:4,ivSize:4,If2x:1,brx8p:2,mO4S:function(e){return{encrypt:function(b,k,d){return("string"==typeof k?c:a).encrypt(e,b,k,d)},decrypt:function(b,k,d){return("string"==typeof k?c:a).decrypt(e,b,k,d)}}}});d.StreamCipher=v.extend({nZ4d:function(){return this.mD4H(!0)},blockSize:1});var b=p.mode={},x=function(e,a,b){var c=this.tC6w;c?this.tC6w=u:c=this.DV9M;for(var d=0;d<b;d++)e[a+d]^=c[d]},q=(d.BlockCipherMode=l.extend({createEncryptor:function(e,a){return this.Encryptor.create(e,a)},createDecryptor:function(e,a){return this.Decryptor.create(e,a)},init:function(e,a){this.ua6U=e;this.tC6w=a}})).extend();q.Encryptor=q.extend({processBlock:function(e,a){var b=this.ua6U,c=b.blockSize;x.call(this,e,a,c);b.encryptBlock(e,a);this.DV9M=e.slice(a,a+c)}});q.Decryptor=q.extend({processBlock:function(e,a){var b=this.ua6U,c=b.blockSize,d=e.slice(a,a+c);b.decryptBlock(e,a);x.call(this,e,a,c);this.DV9M=d}});b=b.CBC=q;q=(p.pad={}).Pkcs7={pad:function(a,b){for(var c=4*b,c=c-a.sigBytes%c,d=c<<24|c<<16|c<<8|c,l=[],n=0;n<c;n+=4)l.push(d);c=s.create(l,c);a.concat(c)},unpad:function(a){a.sigBytes-=a.words[a.sigBytes-1>>>2]&255}};d.BlockCipher=v.extend({cfg:v.cfg.extend({mode:b,padding:q}),reset:function(){v.reset.call(this);var a=this.cfg,b=a.iv,a=a.mode;if(this.UA5F==this.If2x)var c=a.createEncryptor;else c=a.createDecryptor,this.UZ5e=1;this.eR1x=c.call(a,this,b&&b.words)},tt6n:function(a,b){this.eR1x.processBlock(a,b)},nZ4d:function(){var a=this.cfg.padding;if(this.UA5F==this.If2x){a.pad(this.i0x,this.blockSize);var b=this.mD4H(!0)}else b=this.mD4H(!0),a.unpad(b);return b},blockSize:4});var n=d.CipherParams=l.extend({init:function(a){this.mixIn(a)},toString:function(a){return(a||this.formatter).stringify(this)}}),b=(p.format={}).OpenSSL={stringify:function(a){var b=a.ciphertext;a=a.salt;return(a?s.create([1398893684,1701076831]).concat(a).concat(b):b).toString(r)},parse:function(a){a=r.parse(a);var b=a.words;if(1398893684==b[0]&&1701076831==b[1]){var c=s.create(b.slice(2,4));b.splice(0,4);a.sigBytes-=16}return n.create({ciphertext:a,salt:c})}},a=d.SerializableCipher=l.extend({cfg:l.extend({format:b}),encrypt:function(a,b,c,d){d=this.cfg.extend(d);var l=a.createEncryptor(c,d);b=l.finalize(b);l=l.cfg;return n.create({ciphertext:b,key:c,iv:l.iv,algorithm:a,mode:l.mode,padding:l.padding,blockSize:a.blockSize,formatter:d.format})},decrypt:function(a,b,c,d){d=this.cfg.extend(d);b=this.HX2x(b,d.format);return a.createDecryptor(c,d).finalize(b.ciphertext)},HX2x:function(a,b){return"string"==typeof a?b.parse(a,this):a}}),p=(p.kdf={}).OpenSSL={execute:function(a,b,c,d){d||(d=s.random(8));a=w.create({keySize:b+c}).compute(a,d);c=s.create(a.words.slice(b),4*c);a.sigBytes=4*b;return n.create({key:a,iv:c,salt:d})}},c=d.PasswordBasedCipher=a.extend({cfg:a.cfg.extend({kdf:p}),encrypt:function(b,c,d,l){l=this.cfg.extend(l);d=l.kdf.execute(d,b.keySize,b.ivSize);l.iv=d.iv;b=a.encrypt.call(this,b,c,d.key,l);b.mixIn(d);return b},decrypt:function(b,c,d,l){l=this.cfg.extend(l);c=this.HX2x(c,l.format);d=l.kdf.execute(d,b.keySize,b.ivSize,c.salt);l.iv=d.iv;return a.decrypt.call(this,b,c,d.key,l)}})}();(function(){for(var u=CryptoJS,p=u.lib.BlockCipher,d=u.algo,l=[],s=[],t=[],r=[],w=[],v=[],b=[],x=[],q=[],n=[],a=[],c=0;256>c;c++)a[c]=128>c?c<<1:c<<1^283;for(var e=0,j=0,c=0;256>c;c++){var k=j^j<<1^j<<2^j<<3^j<<4,k=k>>>8^k&255^99;l[e]=k;s[k]=e;var z=a[e],F=a[z],G=a[F],y=257*a[k]^16843008*k;t[e]=y<<24|y>>>8;r[e]=y<<16|y>>>16;w[e]=y<<8|y>>>24;v[e]=y;y=16843009*G^65537*F^257*z^16843008*e;b[k]=y<<24|y>>>8;x[k]=y<<16|y>>>16;q[k]=y<<8|y>>>24;n[k]=y;e?(e=z^a[a[a[G^z]]],j^=a[a[j]]):e=j=1}var H=[0,1,2,4,8,16,32,64,128,27,54],d=d.AES=p.extend({mk4o:function(){for(var a=this.J0x,c=a.words,d=a.sigBytes/4,a=4*((this.bgi6c=d+6)+1),e=this.brW8O=[],j=0;j<a;j++)if(j<d)e[j]=c[j];else{var k=e[j-1];j%d?6<d&&4==j%d&&(k=l[k>>>24]<<24|l[k>>>16&255]<<16|l[k>>>8&255]<<8|l[k&255]):(k=k<<8|k>>>24,k=l[k>>>24]<<24|l[k>>>16&255]<<16|l[k>>>8&255]<<8|l[k&255],k^=H[j/d|0]<<24);e[j]=e[j-d]^k}c=this.bse8W=[];for(d=0;d<a;d++)j=a-d,k=d%4?e[j]:e[j-4],c[d]=4>d||4>=j?k:b[l[k>>>24]]^x[l[k>>>16&255]]^q[l[k>>>8&255]]^n[l[k&255]]},encryptBlock:function(a,b){this.DW9N(a,b,this.brW8O,t,r,w,v,l)},decryptBlock:function(a,c){var d=a[c+1];a[c+1]=a[c+3];a[c+3]=d;this.DW9N(a,c,this.bse8W,b,x,q,n,s);d=a[c+1];a[c+1]=a[c+3];a[c+3]=d},DW9N:function(a,b,c,d,e,j,l,f){for(var m=this.bgi6c,g=a[b]^c[0],h=a[b+1]^c[1],k=a[b+2]^c[2],n=a[b+3]^c[3],p=4,r=1;r<m;r++)var q=d[g>>>24]^e[h>>>16&255]^j[k>>>8&255]^l[n&255]^c[p++],s=d[h>>>24]^e[k>>>16&255]^j[n>>>8&255]^l[g&255]^c[p++],t=d[k>>>24]^e[n>>>16&255]^j[g>>>8&255]^l[h&255]^c[p++],n=d[n>>>24]^e[g>>>16&255]^j[h>>>8&255]^l[k&255]^c[p++],g=q,h=s,k=t;q=(f[g>>>24]<<24|f[h>>>16&255]<<16|f[k>>>8&255]<<8|f[n&255])^c[p++];s=(f[h>>>24]<<24|f[k>>>16&255]<<16|f[n>>>8&255]<<8|f[g&255])^c[p++];t=(f[k>>>24]<<24|f[n>>>16&255]<<16|f[g>>>8&255]<<8|f[h&255])^c[p++];n=(f[n>>>24]<<24|f[g>>>16&255]<<16|f[h>>>8&255]<<8|f[k&255])^c[p++];a[b]=q;a[b+1]=s;a[b+2]=t;a[b+3]=n},keySize:8});u.AES=p.mO4S(d)})();
    function RSAKeyPair(a,b,c){this.e=biFromHex(a),this.d=biFromHex(b),this.m=biFromHex(c),this.chunkSize=2*biHighIndex(this.m),this.radix=16,this.barrett=new BarrettMu(this.m)}function twoDigit(a){return(10>a?"0":"")+String(a)}function encryptedString(a,b){for(var f,g,h,i,j,k,l,c=new Array,d=b.length,e=0;d>e;)c[e]=b.charCodeAt(e),e++;for(;0!=c.length%a.chunkSize;)c[e++]=0;for(f=c.length,g="",e=0;f>e;e+=a.chunkSize){for(j=new BigInt,h=0,i=e;i<e+a.chunkSize;++h)j.digits[h]=c[i++],j.digits[h]+=c[i++]<<8;k=a.barrett.powMod(j,a.e),l=16==a.radix?biToHex(k):biToString(k,a.radix),g+=l+" "}return g.substring(0,g.length-1)}function decryptedString(a,b){var e,f,g,h,c=b.split(" "),d="";for(e=0;e<c.length;++e)for(h=16==a.radix?biFromHex(c[e]):biFromString(c[e],a.radix),g=a.barrett.powMod(h,a.d),f=0;f<=biHighIndex(g);++f)d+=String.fromCharCode(255&g.digits[f],g.digits[f]>>8);return 0==d.charCodeAt(d.length-1)&&(d=d.substring(0,d.length-1)),d}function setMaxDigits(a){maxDigits=a,ZERO_ARRAY=new Array(maxDigits);for(var b=0;b<ZERO_ARRAY.length;b++)ZERO_ARRAY[b]=0;bigZero=new BigInt,bigOne=new BigInt,bigOne.digits[0]=1}function BigInt(a){this.digits="boolean"==typeof a&&1==a?null:ZERO_ARRAY.slice(0),this.isNeg=!1}function biFromDecimal(a){for(var d,e,f,b="-"==a.charAt(0),c=b?1:0;c<a.length&&"0"==a.charAt(c);)++c;if(c==a.length)d=new BigInt;else{for(e=a.length-c,f=e%dpl10,0==f&&(f=dpl10),d=biFromNumber(Number(a.substr(c,f))),c+=f;c<a.length;)d=biAdd(biMultiply(d,lr10),biFromNumber(Number(a.substr(c,dpl10)))),c+=dpl10;d.isNeg=b}return d}function biCopy(a){var b=new BigInt(!0);return b.digits=a.digits.slice(0),b.isNeg=a.isNeg,b}function biFromNumber(a){var c,b=new BigInt;for(b.isNeg=0>a,a=Math.abs(a),c=0;a>0;)b.digits[c++]=a&maxDigitVal,a>>=biRadixBits;return b}function reverseStr(a){var c,b="";for(c=a.length-1;c>-1;--c)b+=a.charAt(c);return b}function biToString(a,b){var d,e,c=new BigInt;for(c.digits[0]=b,d=biDivideModulo(a,c),e=hexatrigesimalToChar[d[1].digits[0]];1==biCompare(d[0],bigZero);)d=biDivideModulo(d[0],c),digit=d[1].digits[0],e+=hexatrigesimalToChar[d[1].digits[0]];return(a.isNeg?"-":"")+reverseStr(e)}function biToDecimal(a){var c,d,b=new BigInt;for(b.digits[0]=10,c=biDivideModulo(a,b),d=String(c[1].digits[0]);1==biCompare(c[0],bigZero);)c=biDivideModulo(c[0],b),d+=String(c[1].digits[0]);return(a.isNeg?"-":"")+reverseStr(d)}function digitToHex(a){var b=15,c="";for(i=0;4>i;++i)c+=hexToChar[a&b],a>>>=4;return reverseStr(c)}function biToHex(a){var d,b="";for(biHighIndex(a),d=biHighIndex(a);d>-1;--d)b+=digitToHex(a.digits[d]);return b}function charToHex(a){var h,b=48,c=b+9,d=97,e=d+25,f=65,g=90;return h=a>=b&&c>=a?a-b:a>=f&&g>=a?10+a-f:a>=d&&e>=a?10+a-d:0}function hexToDigit(a){var d,b=0,c=Math.min(a.length,4);for(d=0;c>d;++d)b<<=4,b|=charToHex(a.charCodeAt(d));return b}function biFromHex(a){var d,e,b=new BigInt,c=a.length;for(d=c,e=0;d>0;d-=4,++e)b.digits[e]=hexToDigit(a.substr(Math.max(d-4,0),Math.min(d,4)));return b}function biFromString(a,b){var g,h,i,j,c="-"==a.charAt(0),d=c?1:0,e=new BigInt,f=new BigInt;for(f.digits[0]=1,g=a.length-1;g>=d;g--)h=a.charCodeAt(g),i=charToHex(h),j=biMultiplyDigit(f,i),e=biAdd(e,j),f=biMultiplyDigit(f,b);return e.isNeg=c,e}function biDump(a){return(a.isNeg?"-":"")+a.digits.join(" ")}function biAdd(a,b){var c,d,e,f;if(a.isNeg!=b.isNeg)b.isNeg=!b.isNeg,c=biSubtract(a,b),b.isNeg=!b.isNeg;else{for(c=new BigInt,d=0,f=0;f<a.digits.length;++f)e=a.digits[f]+b.digits[f]+d,c.digits[f]=65535&e,d=Number(e>=biRadix);c.isNeg=a.isNeg}return c}function biSubtract(a,b){var c,d,e,f;if(a.isNeg!=b.isNeg)b.isNeg=!b.isNeg,c=biAdd(a,b),b.isNeg=!b.isNeg;else{for(c=new BigInt,e=0,f=0;f<a.digits.length;++f)d=a.digits[f]-b.digits[f]+e,c.digits[f]=65535&d,c.digits[f]<0&&(c.digits[f]+=biRadix),e=0-Number(0>d);if(-1==e){for(e=0,f=0;f<a.digits.length;++f)d=0-c.digits[f]+e,c.digits[f]=65535&d,c.digits[f]<0&&(c.digits[f]+=biRadix),e=0-Number(0>d);c.isNeg=!a.isNeg}else c.isNeg=a.isNeg}return c}function biHighIndex(a){for(var b=a.digits.length-1;b>0&&0==a.digits[b];)--b;return b}function biNumBits(a){var e,b=biHighIndex(a),c=a.digits[b],d=(b+1)*bitsPerDigit;for(e=d;e>d-bitsPerDigit&&0==(32768&c);--e)c<<=1;return e}function biMultiply(a,b){var d,h,i,k,c=new BigInt,e=biHighIndex(a),f=biHighIndex(b);for(k=0;f>=k;++k){for(d=0,i=k,j=0;e>=j;++j,++i)h=c.digits[i]+a.digits[j]*b.digits[k]+d,c.digits[i]=h&maxDigitVal,d=h>>>biRadixBits;c.digits[k+e+1]=d}return c.isNeg=a.isNeg!=b.isNeg,c}function biMultiplyDigit(a,b){var c,d,e,f;for(result=new BigInt,c=biHighIndex(a),d=0,f=0;c>=f;++f)e=result.digits[f]+a.digits[f]*b+d,result.digits[f]=e&maxDigitVal,d=e>>>biRadixBits;return result.digits[1+c]=d,result}function arrayCopy(a,b,c,d,e){var g,h,f=Math.min(b+e,a.length);for(g=b,h=d;f>g;++g,++h)c[h]=a[g]}function biShiftLeft(a,b){var e,f,g,h,c=Math.floor(b/bitsPerDigit),d=new BigInt;for(arrayCopy(a.digits,0,d.digits,c,d.digits.length-c),e=b%bitsPerDigit,f=bitsPerDigit-e,g=d.digits.length-1,h=g-1;g>0;--g,--h)d.digits[g]=d.digits[g]<<e&maxDigitVal|(d.digits[h]&highBitMasks[e])>>>f;return d.digits[0]=d.digits[g]<<e&maxDigitVal,d.isNeg=a.isNeg,d}function biShiftRight(a,b){var e,f,g,h,c=Math.floor(b/bitsPerDigit),d=new BigInt;for(arrayCopy(a.digits,c,d.digits,0,a.digits.length-c),e=b%bitsPerDigit,f=bitsPerDigit-e,g=0,h=g+1;g<d.digits.length-1;++g,++h)d.digits[g]=d.digits[g]>>>e|(d.digits[h]&lowBitMasks[e])<<f;return d.digits[d.digits.length-1]>>>=e,d.isNeg=a.isNeg,d}function biMultiplyByRadixPower(a,b){var c=new BigInt;return arrayCopy(a.digits,0,c.digits,b,c.digits.length-b),c}function biDivideByRadixPower(a,b){var c=new BigInt;return arrayCopy(a.digits,b,c.digits,0,c.digits.length-b),c}function biModuloByRadixPower(a,b){var c=new BigInt;return arrayCopy(a.digits,0,c.digits,0,b),c}function biCompare(a,b){if(a.isNeg!=b.isNeg)return 1-2*Number(a.isNeg);for(var c=a.digits.length-1;c>=0;--c)if(a.digits[c]!=b.digits[c])return a.isNeg?1-2*Number(a.digits[c]>b.digits[c]):1-2*Number(a.digits[c]<b.digits[c]);return 0}function biDivideModulo(a,b){var f,g,h,i,j,k,l,m,n,o,p,q,r,s,c=biNumBits(a),d=biNumBits(b),e=b.isNeg;if(d>c)return a.isNeg?(f=biCopy(bigOne),f.isNeg=!b.isNeg,a.isNeg=!1,b.isNeg=!1,g=biSubtract(b,a),a.isNeg=!0,b.isNeg=e):(f=new BigInt,g=biCopy(a)),new Array(f,g);for(f=new BigInt,g=a,h=Math.ceil(d/bitsPerDigit)-1,i=0;b.digits[h]<biHalfRadix;)b=biShiftLeft(b,1),++i,++d,h=Math.ceil(d/bitsPerDigit)-1;for(g=biShiftLeft(g,i),c+=i,j=Math.ceil(c/bitsPerDigit)-1,k=biMultiplyByRadixPower(b,j-h);-1!=biCompare(g,k);)++f.digits[j-h],g=biSubtract(g,k);for(l=j;l>h;--l){for(m=l>=g.digits.length?0:g.digits[l],n=l-1>=g.digits.length?0:g.digits[l-1],o=l-2>=g.digits.length?0:g.digits[l-2],p=h>=b.digits.length?0:b.digits[h],q=h-1>=b.digits.length?0:b.digits[h-1],f.digits[l-h-1]=m==p?maxDigitVal:Math.floor((m*biRadix+n)/p),r=f.digits[l-h-1]*(p*biRadix+q),s=m*biRadixSquared+(n*biRadix+o);r>s;)--f.digits[l-h-1],r=f.digits[l-h-1]*(p*biRadix|q),s=m*biRadix*biRadix+(n*biRadix+o);k=biMultiplyByRadixPower(b,l-h-1),g=biSubtract(g,biMultiplyDigit(k,f.digits[l-h-1])),g.isNeg&&(g=biAdd(g,k),--f.digits[l-h-1])}return g=biShiftRight(g,i),f.isNeg=a.isNeg!=e,a.isNeg&&(f=e?biAdd(f,bigOne):biSubtract(f,bigOne),b=biShiftRight(b,i),g=biSubtract(b,g)),0==g.digits[0]&&0==biHighIndex(g)&&(g.isNeg=!1),new Array(f,g)}function biDivide(a,b){return biDivideModulo(a,b)[0]}function biModulo(a,b){return biDivideModulo(a,b)[1]}function biMultiplyMod(a,b,c){return biModulo(biMultiply(a,b),c)}function biPow(a,b){for(var c=bigOne,d=a;;){if(0!=(1&b)&&(c=biMultiply(c,d)),b>>=1,0==b)break;d=biMultiply(d,d)}return c}function biPowMod(a,b,c){for(var d=bigOne,e=a,f=b;;){if(0!=(1&f.digits[0])&&(d=biMultiplyMod(d,e,c)),f=biShiftRight(f,1),0==f.digits[0]&&0==biHighIndex(f))break;e=biMultiplyMod(e,e,c)}return d}function BarrettMu(a){this.modulus=biCopy(a),this.k=biHighIndex(this.modulus)+1;var b=new BigInt;b.digits[2*this.k]=1,this.mu=biDivide(b,this.modulus),this.bkplus1=new BigInt,this.bkplus1.digits[this.k+1]=1,this.modulo=BarrettMu_modulo,this.multiplyMod=BarrettMu_multiplyMod,this.powMod=BarrettMu_powMod}function BarrettMu_modulo(a){var i,b=biDivideByRadixPower(a,this.k-1),c=biMultiply(b,this.mu),d=biDivideByRadixPower(c,this.k+1),e=biModuloByRadixPower(a,this.k+1),f=biMultiply(d,this.modulus),g=biModuloByRadixPower(f,this.k+1),h=biSubtract(e,g);for(h.isNeg&&(h=biAdd(h,this.bkplus1)),i=biCompare(h,this.modulus)>=0;i;)h=biSubtract(h,this.modulus),i=biCompare(h,this.modulus)>=0;return h}function BarrettMu_multiplyMod(a,b){var c=biMultiply(a,b);return this.modulo(c)}function BarrettMu_powMod(a,b){var d,e,c=new BigInt;for(c.digits[0]=1,d=a,e=b;;){if(0!=(1&e.digits[0])&&(c=this.multiplyMod(c,d)),e=biShiftRight(e,1),0==e.digits[0]&&0==biHighIndex(e))break;d=this.multiplyMod(d,d)}return c}var maxDigits,ZERO_ARRAY,bigZero,bigOne,dpl10,lr10,hexatrigesimalToChar,hexToChar,highBitMasks,lowBitMasks,biRadixBase=2,biRadixBits=16,bitsPerDigit=biRadixBits,biRadix=65536,biHalfRadix=biRadix>>>1,biRadixSquared=biRadix*biRadix,maxDigitVal=biRadix-1,maxInteger=9999999999999998;setMaxDigits(20),dpl10=15,lr10=biFromNumber(1e15),hexatrigesimalToChar=new Array("0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z"),hexToChar=new Array("0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f"),highBitMasks=new Array(0,32768,49152,57344,61440,63488,64512,65024,65280,65408,65472,65504,65520,65528,65532,65534,65535),lowBitMasks=new Array(0,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,16383,32767,65535);
    
  • 上面代码补充进wyy.js中之后,就可以运行生成params和encSecKey,这样每首歌曲都会生成这样一对表单数据作为参数,再由这些参数构架歌曲的地址了。如图所示。
    在这里插入图片描述
  • 显然,上面得到的结果,分别是params的值encText,以及encSecKey的值encSecKey,这也是表单数据里面的形式。经过一系列操作,把表单数据信息的加密逻辑分析明白后,再逆向读取,用Python重新模拟生成了。再看看下面的代码,是不是觉得,也不十分陌生了吧。
    在这里插入图片描述

二、开始爬取工作

1、构建歌曲地址

  • 改写get_music_url_index方法,把歌曲id和名称都加入。代码如下:
        def get_data_index(self):
            resp = requests.post(url=self.url, data=self.data, headers=self.headers)
            # print(resp.text)
            # 此处根据web?csrf_token=链接汇总的预览栏,找到字典形式的信息,获取相应歌曲名
            dict_data = json.loads(resp.text)["result"]["songs"]
            # 而后遍历所有歌曲,获取name和id
            for data in dict_data:
                name = data["name"]
                id = data["id"]
                # print(name, id)
                self.get_music_url_index(id, name)
    
        # 定义获取歌曲地址信息的方法,注意这里加入歌曲的参数id
        def get_music_url_index(self, id, name):
            content = open("wyy.js", "r", encoding="utf-8").read()
            data_js = execjs.compile(content)
            sign = data_js.call("start", id)
            # 通过下面打印输出的结果,看出来表单数据的构造方法成功了
            # print(sign)
            # 应用上面构造的方法,生成表单数据
            data = {
                "params": sign["encText"],
                "encSecKey": sign["encSecKey"]
            }
            # 定义歌曲链接,获取源代码
            resp = requests.post(url=self.music_url, data=data, headers=self.headers).text
            music_url = json.loads(resp)["data"][0]["url"]
            print(music_url, name)
    

2、修改JS文件中的参数

  • 上面代码写完后,相应的,wyy.js里面的start函数里面,也要加上id参数。如图。
    在这里插入图片描述

3、成功获得歌曲链接的地址

  • 效果如图。
    在这里插入图片描述

三、保存并总结

  • 由两段代码构成,首先在Music_Data类的前面写一个判断,判断根目录下有没有文件夹,没有的话就创建。
    file_name = input("请手动创建保存歌曲的文件夹:")
    if not os.path.exists(file_name):
        os.mkdir(file_name)
    
  • 再到Music_Data类的里面,写一个保存的方法write_music,代码如下:
    # 保存
    def write_music(self, music_url, name):
        try:
            with open(f"./{file_name}/"+name+".mp3", "wb") as f:
                resp = requests.get(music_url).content
                f.write(resp)
                print(name, "----保存成功")
        except Exception as e:
            print(e)
    
  • 运行一下程序,得到想要的结果。如图。
    在这里插入图片描述
  • 打开歌曲所在的文件夹,也能看到,成功。
    在这里插入图片描述
  • 总结如下:
    • 以上是用js逆向的方法完成歌曲的爬取下载。用到了JavaScript技术,那么这个技术也需要熟练掌握,不然爬虫技术也是无法突破。
    • 本例中,首先找到token的信息,把里面歌曲的链接地址,包括生成这个地址的加密形式的表单数据,以及歌曲的id和name都找到。然后,进一步寻找表单数据的加密逻辑,创建相应的js文件。最后,继续编写主程序代码,把构建歌曲地址的方法,以及保存歌曲的方法写入,最后成功运行。
    • 当然,不用逆向,通过分析网页,预览源代码,用json方法获取字典形式的歌曲url,也是能实现爬取歌曲的目的。不过本节学习逆向方法,就绕了这么一大弯。
    • 真正遇到加密性强的网站,本节练习的内容,权当是爬虫逆向的入门知识了。
    • 注:想要源码的问一下anqiuxiguanli

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/309.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

XXE漏洞复现

目录XML基础概念XML数据格式DTD基础定义DTD作用分类DTD实体实体的分类DTD元素XXE漏洞介绍实操如何探测xxe漏洞XML基础 概念 什么是XML 是一种可扩展标记语言 (Extensible Markup Language, XML) &#xff0c;标准通用标记语言的子集&#xff0c;可以用来标记数据、定义数据类型…

30个题型+代码(冲刺2023蓝桥杯)(中)

2023.3.13~4.13持续更新 目录 &#x1f34e;注意 &#x1f33c;前言 &#x1f33c;十&#xff0c;KMP&#xff08;留坑&#xff09; &#x1f33c;十一&#xff0c;Trie&#xff08;留坑&#xff09; &#x1f33c;十二&#xff0c;BFS &#x1f44a;(一)1562. 微博转发…

OpenAI 发布GPT-4——全网抢先体验

OpenAI 发布GPT-4 最近 OpenAI 犹如开挂一般&#xff0c;上周才刚刚推出GPT-3.5-Turbo API&#xff0c;今天凌晨再次祭出GPT-4这个目前最先进的多模态预训练大模型。与上一代GPT3.5相比&#xff0c;GPT-4最大的飞跃是增加了识图能力&#xff0c;并且回答准确性也得到显著提高。…

写给20、21级学生的话

写给20、21级学生的话前言一、关于招聘变招生&#xff0c;你怎么看&#xff1f;二、对于即将实习/已经实习的学生&#xff0c;你有什么建议&#xff1f;1.学习方面2.提升方面三、思想成年真的很重要前言 最近&#xff0c;有一些同学遇到的实习问题&#xff0c;我统一回复下&…

第十二届蓝桥杯省赛详解

试题A&#xff1a;空间 1B是8位&#xff0c;32位二进制数占用4B空间&#xff0c;1MB2^10KB2^20B 那么可以存放32位二进制数的个数为256*2^20*8/3267108864 试题B&#xff1a;卡片 分析&#xff1a;因为数据只有2021&#xff0c;所以直接模拟即可 结果为&#xff1a;3181&…

MySQL基础------sql指令1.0(查询操作->select)

目录 前言&#xff1a; 单表查询 1.查询当前所在数据库 2.查询整个表数据 3.查询某字段 4.条件查询 5.单行处理函数&#xff08;聚合函数&#xff09; 6.查询时给字段取别名 7.模糊查询 8.查询结果去除重复项 9.排序&#xff08;升序和降序&#xff09; 10. 分组查询 1…

Linux 如何使用 git | 新建仓库 | git 三板斧

文章目录 专栏导读 一、如何安装 git 二、注册码云账号 三、新建仓库 配置仓库信息 四、克隆远端仓库到本地 五、git 三板斧 1. 三板斧第一招&#xff1a;git add 2. 三板斧第二招&#xff1a;git commit 解决首次 git commit 失败的问题 配置机器信息 3. 三…

最新!Windows 11 更新将整合 AI 技术

微软MVP实验室研究员张雅琪&#xff08;阿法兔&#xff09;微软最有价值专家&#xff08;MVP&#xff09;&#xff0c;毕业于外交学院和香港大学&#xff0c;IT 技术社区创始人&#xff0c;中关村互联网金融研究院兼职研究员&#xff0c;多次受邀在微软 Reactor 进行公开演讲&a…

电子工程师必须掌握的硬件测试仪器,你确定你都掌握了?

目录示波器示例1&#xff1a;测量示波器自带的标准方波信号输出表笔认识屏幕刻度认识波形上下/左右移动上下/左右刻度参数调整通道1的功能界面捕获信号设置Menu菜单触发方式触发电平Cursor按钮捕捉波形HLEP按钮参考资料频谱分析仪器信号发生器示波器 示例1&#xff1a;测量示波…

STM32F103R8T6 SPWM实现正弦波输出

前言 PWM合成正弦波&#xff0c;原理什么的不详细说了&#xff0c;概括一下就是 PWM有效面积的积分 正弦波的有效面积。PWM的频率越快&#xff0c;细分的越多&#xff0c;锯齿也就越不明显。 做法是&#xff1a;首先利用正弦波取点软件&#xff0c;取点1000个&#xff0c;生…

求职(怎么才算精通JAVA开发)

在找工作的的时候,有时候我们需要对自己的技术水平做一个评估。特别是Java工程师,我们该怎么去表达自己的能力和正确认识自己所处的技术水平呢。技术一般的人,一般都不敢说自己精通JAVA,因为你说了精通JAVA几乎就给了面试官一个可以随便往死里问的理由了。很多不自信的一般…

《ChatGPT是怎样炼成的》

ChatGPT 在全世界范围内风靡一时&#xff0c;我现在每天都会使用 ChatGPT 帮我回答几个问题&#xff0c;甚至有的时候在一天内我和它对话的时间比和正常人类对话还要多&#xff0c;因为它确实“法力无边&#xff0c;功能强大”。 ChatGPT 可以帮助我解读程序&#xff0c;做翻译…

在 4G 内存的机器上,申请 8G 内存会怎么样?

在 4GB 物理内存的机器上&#xff0c;申请 8G 内存会怎么样&#xff1f; 这个问题在没有前置条件下&#xff0c;就说出答案就是耍流氓。这个问题要考虑三个前置条件&#xff1a; 操作系统是 32 位的&#xff0c;还是 64 位的&#xff1f;申请完 8G 内存后会不会被使用&#x…

cmd命令教程

小提示&#xff1a; 在本文中&#xff0c;我将向您展示可以在 Windows 命令行上使用的 40 个命令 温馨提示&#xff1a;在本教程中学习使用适用于 Windows 10 和 CMD 网络命令的最常见基本 CMD 命令及其语法和示例 文章目录为什么命令提示符有用一、cmd是什么&#xff1f;如何在…

一年经验年初被裁面试1月有余无果,还遭前阿里面试官狂问八股,人麻了

最近接到一粉丝投稿&#xff1a;年初被裁员&#xff0c;在家躺平了6个月&#xff0c;然后想着学习下再去面试&#xff0c;现在面试了1个月有余&#xff0c;无果&#xff0c;天天打游戏到半夜&#xff0c;根本无法静下心来学习。下面是他这些天面试经常会被问到的一些问题&#…

手机解锁方法:8个顶级的 Android 手机解锁软件

一般来说&#xff0c;太简单的密码是不安全的&#xff0c;所以我们设置一个安全的密码&#xff0c;可能会稍微复杂一点。然而&#xff0c;我们可能经常会忘记复杂的密码并锁定我们的 Android 智能手机。 8个顶级的 Android 手机解锁软件 如果您遇到过这种情况并且正在寻找一种…

【Android -- 软技能】聊聊程序员的软技能

什么是软技能&#xff1f; 所谓软技能&#xff0c;就是相对于「硬技能」而言的技能&#xff0c;对于程序员来说&#xff0c;「硬技能」就是计算机专业技术能力&#xff0c;软技能则是专业之外的所有技能&#xff0c;包括职业规划能力、处理人际关系能力、专业态度、做事的方式…

linux基本功系列之uname实战

文章目录前言一. uname命令介绍二. 语法格式及常用选项三. 参考案例3.1 输出全部信息3.2 输出内核名称及版本3.3 输出网络节点的主机名3.4 输出主机硬件架构3.5 输出操作系统名称3.6 显示版本信息总结前言 大家好&#xff0c;又见面了&#xff0c;我是沐风晓月&#xff0c;本文…

初入了解——什么是VUE

个人简介&#xff1a;云计算网络运维专业人员&#xff0c;了解运维知识&#xff0c;掌握TCP/IP协议&#xff0c;每天分享网络运维知识与技能。座右铭&#xff1a;海不辞水&#xff0c;故能成其大&#xff1b;山不辞石&#xff0c;故能成其高。个人主页&#xff1a;小李会科技的…

Java中的反射

类加载器&#xff08;1&#xff09;类的加载当我们的程序在运行后&#xff0c;第一次使用某个类的时候&#xff0c;会将此类的class文件读取到内存&#xff0c;并将此类的所有信息存储到一个Class对象中。说明&#xff1a;a.图中的Class对象是指&#xff1a;java.lang.Class类的…