教你学会网易云JS逆向,爬来的歌打包发给女友邮箱可好?

开发 前端
就和标题一样,这次打算解析一下 网易云 请求的参数,然后把爬来的歌曲编写到前端html代码里面,最后用代码实现QQ邮箱的发送功能,嗯,没错,确实创新了一点,但是在编写代码的框架思路上, 每个人都是有所不同, 找到自己的方法就可以了。

前言:

最近点赞了一些文章,觉得有些东西是我还没有接触过的,于是打算复刻一次,但是用我的思路,加上一些新的想法,最后我也是成功实现了这些功能。

就和标题一样,这次打算解析一下 网易云 请求的参数,然后把爬来的歌曲编写到前端html代码里面,最后用代码实现QQ邮箱的发送功能,嗯,没错,确实创新了一点,但是在编写代码的框架思路上, 每个人都是有所不同, 找到自己的方法就可以了。

我本以为用python实现了它的加密算法之后,可以解析(very import person) 歌曲, 但是根据我的实际操作上,是不可以的,后面也会讲到,他们加密的参数是不一样的,都有各自的播放渠道, 如果你熟悉 html 你都可以发现他有二个播放渠道, 分别对应一般和特殊,所以后面我直接就开了黑胶会员, 我就想知道参数到底有什么不同, 不幸的是,当我在网页端登入账号的时候, 我发现在我打断点之后,我就不能启动调试功能了,相反的是 debugger parse 这样的字段,我尝试去解决这个问题,根据网上各种方式,到后面还是无济于事,索性放弃了,但是对于一般的 music , 是完全没有问题的,都可以下载,发送,保存到本地。

后面当我把这代码全部写好,加上了一些异常处理,我想到我的憨憨女友,索性在加一点代码实现,就把这些爬来的数据 写道一个 /

里面, 然后再用其他函数库发送到她邮箱去了,单纯觉得好玩。

这篇文章有点长,因为有点难懂, 我只是想讲清楚一点,给她看,或者 给一些基础不是很好的人看一下, 大佬可以亲喷点,代码用到了很多库,但是我再后面也会一个个提到,不影响各位阅读, 只要耐心的看,你就一定有收获。

文章三天之后设置为粉丝可见。

歌曲版权最终归网易云所有!

[[343388]]

JS逆向, ASE加密, RES非对称算法,yagmail邮箱的发送,浏览器的debug,学到就是爽。

效果图:

就是一个 html 表格, 熟悉的应该就直接能看出来, 然后还有img标签, a标签之类的。

页面分析:

当我们用chrome浏览器 (推荐用谷歌) 进入网易云官网,找到一首你喜欢的歌。

打开 f12 功能, 点击 XHR 过滤, 这个时候,我们点击播放, 在右侧就会重新捕获到新的网络请求,其中就包括我们需要的歌曲文件链接。就像这样。

 

教你学会网易云JS逆向,爬来的歌打包发给女友邮箱可好?

v1?csrf … 这个网址就是刚刷的, 在响应中可以看到,有个url,你复制打开,就可以直接播放, 我们点击一下headers看看怎么发送的。

请求了request url , 用post发送, 下面有2个参数表单 params 和 encSecKey 貌似我们有下面2个参数就可以直接发送请求了, 所以直接就尝试了一下。

  1. def spider(self): 
  2.     ""
  3.     这是爬取一首歌的方式, 复制params就可以发送请求 
  4.     ""
  5.     r = requests.post(self.params_url, params=self.params)        if r.status_code == 200: 
  6.         mp3 = r.json().get("data")[0].get("url"
  7.         rmp3 = requests.get(mp3, headers={"user-agent": self.ua}) 
  8.         if rmp3.status_code == 200: 
  9.             with open("像鱼.mp3"'wb'as ;fw: 
  10.                 ;fw.write(rmp3.content)                print("下载成功"

最后成功下载。

也就是说,我们只需要知道这二个参数怎么来的,就可以自己构造了,那就想怎么就怎么了,这个时候,我们就可以打开浏览器自带的调试功能了。要打断点,要debug, 怎么打,怎么断? 仔细点看我图的注释就可以了。

还是之前的包, 你点击第四个 initiator 就会刷新出很多和他有关系的文件, 我们点击第一个。

然后就来到这样, 还记得之前的二个参数吧, 在这里我们直接 ctrl + f 找其中的一个参数。

这里可以看到 params , encSecKey 都是根据 bvz7s 来的, 而bvz7s 是根据 window.asrsea() 函数来的, 所以在这个 函数打一个断点, 继续看下一个搜索点

在这里,我们发现window.asrsea = d 所以就得看 d 函数,在d函数的语气中,我们都可以打上断点,以便观察清楚。 打上断电之后, 刷新页面,等待一段时间。

之后就到第一个断点处, 然后 f8 跳到下一个断点

然后就可以发现 d 接受的4个参数是什么了, (d, e, f, g) 在右侧我们也可以看到,多次测试发现,后面三个是加密参数,固定值,所以复制拿过来用就可以了, 对于第一个d = {“csrf_token”:"…"} 这个是用来记录你是否登入账号, 如果你没有登陆, 那就是空。

继续f8 跳转到最后

发现就是把最开始接受的4个参数,然后经过a, b, b, c 函数处理就可以了,那待会我们就要看看每个函数有什么作用,这就涉及到他们的加密方式了,但是在这里,就要思考一个问题了,关于最开始的4个参数, 就一个d会变, 其他都没变化, 而且d还是一个空或者乱七八糟的的数字, 那他是怎么知道我是哪一首歌? 哪个歌手,所以这个参数一定有问题, (后面经过加密测试,发现加密后参数长度少了很多) 所以在这里我就继续 调试了一下, 一样的操作。

调试一圈了,最后终于有一个靠谱的了,有歌曲的id 还有歌曲的音质, 其他的,如果不熟悉,可以每一个d都去试试,直到加密参数正确。

所以先确定d为

  1. "{"ids":"[1459950258]","level":"standard","encodeType":"aac","csrf_token":"59098e191e8babbaef83f1b8bbbe5987"}" 

姑且就用这个d参数去加密尝试一次吧。

参数加密:

  • 回到之前d函数的区域,就在d的上面,我们就可以看到a,b,c 函数的执行过程。

我们只需要一个个了解好,然后用python语言转换一下就可以了。下面分模块讲这些。

函数function A:

  1. function a(a) { 
  2.         var d, e, b = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789", c = ""
  3.         for (d = 0; a > d; d += 1) 
  4.             e = Math.random() * b.length, 
  5.             e = Math.floor(e), 
  6.             c += b.charAt(e);        return c 
  7.     } 

熟悉的一看就知道, a函数接受一个a参数, 然后再一次循环中, 循环一次为a次, 然后从 b中 随机的挑选一些字符, 最后用字符串的形式返回, 对于Javascript来说,随机没那么容易,他需要用 random 生成 (0, 1) 的数,然后放大,取整,取值,累加,但对于python来说, 如下:

  1. def SimulateFunctionA(self, length=None): 
  2.        ""
  3.        @JavaScript 
  4.         function a(a) { 
  5.        var d, e, b = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789", c = ""
  6.        for (d = 0; a > d; d += 1) 
  7.            e = Math.random() * b.length, 
  8.            e = Math.floor(e), 
  9.            c += b.charAt(e); 
  10.        return c 
  11.    } 
  12.        length :  16 
  13.        using the python get the c 
  14.        ""
  15.        b = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789' 
  16.        c = random.sample(b, length)        return "".join(c) 

简单.

函数function B:

  1. function b(a, b) { 
  2.        var c = CryptoJS.enc.Utf8.parse(b) 
  3.          , d = CryptoJS.enc.Utf8.parse("0102030405060708"
  4.          , e = CryptoJS.enc.Utf8.parse(a)          , f = CryptoJS.AES.encrypt(e, c, {            iv: d, 
  5.            mode: CryptoJS.mode.CBC 
  6.        });        return f.toString() 
  7.    } 

这是一个 AES 加密, 模式 CBC, 其实刚开始我也不知道AES加密是什么东西, 后面我查看了官网文档,参考了其他的办法,实现了。

观察这个函数, 接受了a,b, 其中a,b 是什么可以再函数d中看到到。

根据之前的分析, g是固定值,我们已经复制下来, d 认为是一个字符字典

  1. "{"ids":"[1459950258]","level":"standard","encodeType":"aac","csrf_token":"59098e191e8babbaef83f1b8bbbe5987"}" 

这样,我们用python语言加入这些参数,试着模拟一下。

  1. def SimulateFunctionB(self, d, key): 
  2.        ""
  3.         function b(a, b) { 
  4.        var c = CryptoJS.enc.Utf8.parse(b) 
  5.          , d = CryptoJS.enc.Utf8.parse("0102030405060708"
  6.          , e = CryptoJS.enc.Utf8.parse(a) 
  7.          , f = CryptoJS.AES.encrypt(e, c, { 
  8.            iv: d, 
  9.            mode: CryptoJS.mode.CBC 
  10.        }); 
  11.        return f.toString() 
  12.    } 
  13.    a =  `"{"ids":"[1459950258]","level":"standard","encodeType":"aac","csrf_token":"59098e191e8babbaef83f1b8bbbe5987"}"
  14.    b = key = self.g(first) = SimulateFunctionA()(second
  15.        ""
  16.        key = key.encode()        iv = self.iv.encode() 
  17.        aes = AES.new(key=key, mode=AES.MODE_CBC, iv=iv)        text = pad(data_to_pad=d.encode(), block_size=AES.block_size)        aes_text = aes.encrypt(plaintext=text)        aes_texts = base64.b64encode(aes_text).decode()        return aes_texts 
  18. SimulateFunticonB(d=" `"{"ids":"[1459950258]","level":"standard","encodeType":"aac","csrf_token":"59098e191e8babbaef83f 

这里也是成功实现了,截图我忘记截了。 关于如何AES加密,可以直接看我的,有时间有兴趣的也可以和我一样看官网文档。 都行, 实现就可以了。

函数function C:

  1. function c(a, b, c) { 
  2.     var d, e; 
  3.     return setMaxDigits(131), 
  4.     d = new RSAKeyPair(b,"",c), 
  5.     e = encryptedString(d, a)    } 

一看很简单,其实复杂, 用到了RSA加密算法,关于RSA加密算法,我找了一些资料。

大致原理如图:

参考文档

我们用python这样实现;

  1. def SimulateFunctionC(self, random16): 
  2.     ""
  3.     a = 131 
  4.     RSA加密原理 
  5.     # num = pow(x, y) % z 
  6.     # 加密C=M^e mod n 
  7.     ""
  8.     e = self.e        f = self.f        text = random16[::-1] 
  9.     num = pow(int(text.encode().hex(), 16), int(e, 16), int(f, 16)) 
  10.     return format(num, 'x').zfill(131)  # TODO: last the num  change the hex  digit and left fill (131) 

pow() 其实是可以接受三个参数的, 如果有第三个, 第三个就为取余值, 用上int(a, 16) 就可以直接将16进制转换为10进制, 最后的format(num, ‘x’) 将值用16进制形式输出, 然后zfill() 填充131 位数,, (根据函数C得知 位数为131)

连贯加密函数类:

分析了上面三个函数, 其实我们就可以直接编写程序加密了, 我们把程序连起来。

  1. # -*- coding :  utf-8 -*- 
  2. # @Time      :  2020/9/15  15:45 
  3. # @author    :  沙漏在下雨# @Software  :  PyCharm# @CSDN      :  https://me.csdn.net/qq_45906219import requestsfrom get_useragent import GetUserAgentCSimport randomfrom Crypto.Util.Padding import padfrom Crypto.Cipher import AESimport base64class GetParams(object):    def __init__(self):        self.ua = GetUserAgentCS().get_user()        self.params_url = 'https://music.163.com/weapi/song/enhance/player/url/v1?csrf_token=' 
  4.         self.e = "010001" 
  5.         self.g = "0CoJUm6Qyw8W8jud" 
  6.         self.iv = '0102030405060708' 
  7.         self.f = "00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7b725152b3ab17a" \ 
  8.                  "876aea8a5aa76d2e417629ec4ee341f56135fccf695280104e0312ecbda92557c93870114af6c9" \ 
  9.                  "d05c4f7f0c3685b7a46bee255932575cce10b424d813cfe4875d3e82047b97ddef52741d546b8e28" \ 
  10.                  "9dc6935b3ece0462db0a22b8e7" 
  11.         self.params = None    def SimulateFunctionA(self, length=None):        ""
  12.         @JavaScript 
  13.          function a(a) { 
  14.         var d, e, b = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789", c = ""
  15.         for (d = 0; a > d; d += 1) 
  16.             e = Math.random() * b.length, 
  17.             e = Math.floor(e), 
  18.             c += b.charAt(e); 
  19.         return c 
  20.     } 
  21.         length :  16 
  22.         using the python get the c 
  23.         ""
  24.         b = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789' 
  25.         c = random.sample(b, length) 
  26.         return "".join(c) 
  27.     def SimulateFunctionB(self, d, key):        ""
  28.          function b(a, b) { 
  29.         var c = CryptoJS.enc.Utf8.parse(b) 
  30.           , d = CryptoJS.enc.Utf8.parse("0102030405060708"
  31.           , e = CryptoJS.enc.Utf8.parse(a) 
  32.           , f = CryptoJS.AES.encrypt(e, c, { 
  33.             iv: d, 
  34.             mode: CryptoJS.mode.CBC 
  35.         }); 
  36.         return f.toString() 
  37.     } 
  38.     a = "{"csrf_token":""}" 
  39.     b = key = self.g(first) = SimulateFunctionA()(second
  40.         ""
  41.         key = key.encode()        iv = self.iv.encode()        aes = AES.new(key=key, mode=AES.MODE_CBC, iv=iv)        text = pad(data_to_pad=d.encode(), block_size=AES.block_size)        aes_text = aes.encrypt(plaintext=text)        aes_texts = base64.b64encode(aes_text).decode()        return aes_texts 
  42.     def SimulateFunctionC(self, random16):        ""
  43.         a = 131 
  44.         RSA加密原理 
  45.         # num = pow(x, y) % z 
  46.         # 加密C=M^e mod n 
  47.         ""
  48.         e = self.e        f = self.f        text = random16[::-1] 
  49.         num = pow(int(text.encode().hex(), 16), int(e, 16), int(f, 16)) 
  50.         return format(num, 'x').zfill(131)  # TODO: last the num  change the hex  digit and left fill (131) 
  51.     def spider(self):        ""
  52.         这是爬取一首歌的方式, 复制params就可以发送请求 
  53.         ""
  54.         r = requests.post(self.params_url, params=self.params)        if r.status_code == 200: 
  55.             mp3 = r.json().get("data")[0].get("url"
  56.             rmp3 = requests.get(mp3, headers={"user-agent": self.ua}) 
  57.             if rmp3.status_code == 200: 
  58.                 with open("像鱼.mp3"'wb'as ;fw: 
  59.                     ;fw.write(rmp3.content) 
  60.                 print("下载成功"
  61.     def get_encrypt_params(self, d=None):        ""
  62.         The function can encrypt your params if you give me a d 
  63.         @params:  d   debug your chrome browser 
  64.         ""
  65.         i = self.SimulateFunctionA(length=16) 
  66.         encText = self.SimulateFunctionB(d, self.g)        encText = self.SimulateFunctionB(encText, i)        encSecKey = self.SimulateFunctionC(random16=i)        return { 
  67.             "params": encText, 
  68.             "encSecKey": encSecKey 
  69.         }# a = GetParams()# a.spider() 

说到底,我们还是要歌曲的id, 怎么来的,就需要继续看下去了。

ID获取:

获取免费单首ID:

直接这样就可以了。

获取id列表:

如果你是进入歌手表单在这个界面,你是找不到需要的id表单数据的,在这里就要用selenium 去爬取然后分析了,

如果你在下面的情况下,就可以找到id表单数据。

还有一样的,在这个包,我们看到参数还是params 和 encSerKey 然后重复上面操作, 打断点调试,甚至加密方式都是一样,不断的打断点,最后发现d是这样的

{"hlpretag":"","hlposttag":"","s":"许嵩","type":"1","offset":"0","total":"true","limit":"30","csrf_token":""}

我们更改一下s的值, 歌曲名称 歌手 都可以, 构建好这个字典, 发送这个网址,就可以得到id了, 然后拿着id去继续构造上面的d值, 就可以拿到歌曲url了。

如下:

 

  1. # -*- coding :  utf-8 -*- 
  2. # @Time      :  2020/9/17  14:59 
  3. # @author    :  沙漏在下雨# @Software  :  PyCharm# @CSDN      :  https://me.csdn.net/qq_45906219from GetParams import GetParamsimport requestsfrom get_useragent import GetUserAgentCSimport randomimport keyringimport yagmailclass DownMp3(object):    def __init__(self):        self.GetIdUrl = "https://music.163.com/weapi/cloudsearch/get/web?csrf_token=" 
  4.         self.GetMP3Url = 'https://music.163.com/weapi/song/enhance/player/url/v1?csrf_token=' 
  5.         self.ua = GetUserAgentCS().get_user()        self.headers = {"User-Agent": self.ua} 
  6.         self.MUSIC_LIST = []  # The singer music demo list        self.Sented_qq_email = self.get_email()    def get_email(self):        email_list = input("输入QQ邮箱 如果你有多个 请用空格隔开:").split() 
  7.         if len(email_list) == 1: 
  8.             if "@qq.com" not in email_list[0]: 
  9.                 raise Exception("邮箱规格好像不合适,你输入的是 ", email_list[0]) 
  10.             else
  11.                 return email_list[0] 
  12.         elif len(email_list) >= 2: 
  13.             for i in email_list: 
  14.                 if "@qq.com" not in i: 
  15.                     raise Exception("邮箱规格好像不合适,你输入的是 ", i) 
  16.                 else
  17.                     pass            return email_list 
  18.     def my_request(self, url, model="get", params=None): 
  19.         if model == 'post'
  20.             r = requests.post(url, headers=self.headers, params=params)            if r.status_code == 200: 
  21.                 r.encoding = r.apparent_encoding                s = r.json()                return s 
  22.         elif model == 'get'
  23.             r = requests.get(url, headers=self.headers, params=params)            if r.status_code == 200: 
  24.                 return r.content 
  25.         else
  26.             raise Exception("method is error !"
  27.     def get_mp3_id_demo(self, start=None):        ""
  28.         get the mp3 id 
  29.         {"hlpretag":"<span class=\"s-fc7\">","hlposttag":"</span>","s":"本兮","type":"1","offset":"0","total":"true","limit":"30","csrf_token":""
  30.         ""
  31.         if start is None: 
  32.             raise Exception("You should enter a start name, but you enter start =", start) 
  33.         d = { 
  34.             "hlpretag""<span class=\"s-fc7\">"
  35.             "hlposttag""</span>"
  36.             "s": str(start), 
  37.             "type""1"
  38.             "offset""0"
  39.             "total""true"
  40.             "limit""30"
  41.             "csrf_token""" 
  42.         }        params = GetParams().get_encrypt_params(str(d))        return self.my_request(self.GetIdUrl, model="post", params=params)["result"]["songs"
  43.     def get_mp3_url(self, id):        ""
  44.         params: id  the music of id 
  45.         fix  the id into "{"ids":"[35440198]","level":"standard","encodeType":"aac","csrf_token":""}" 
  46.         so we can get the music the downpath 
  47.         ""
  48.         d = {"ids": str([id]), "level""standard""encodeType""aac""csrf_token"""
  49.         params = GetParams().get_encrypt_params(str(d))        context = self.my_request(self.GetMP3Url, model="post", params=params) 
  50.         mp3_path_url = context.get("data")[0]["url"
  51.         return mp3_path_url 
  52.     def print_id_list(self, id_list):        ""
  53.         params: id_list  print the singer about 30s  musics 
  54.         ""
  55.         a = {}        for index, value in enumerate(id_list): 
  56.             a['count'] = (index + 1) 
  57.             a["singer_name"] = value.get("name"
  58.             a["id"] = value.get("id"
  59.             a["album"] = value.get("al").get("name"
  60.             a["image"] = value.get("al").get("picUrl"
  61.             self.MUSIC_LIST.append(a.copy())    def random_get_mp3(self):        mp3Ten = random.sample(self.MUSIC_LIST, 10)  # 提出十首歌 
  62.         content = ""  # 把数据写入html中 方便发送 
  63.         content += '<p><font size="20" color="Tan">Happy day for you !</font></p>' 
  64.         content += '<table border="1" style="border-collapse: collapse;">\n<caption>Today music demo </caption>\n<tr><th>序号</th><th>歌曲名</th><th>歌曲链接</th><th>歌曲所属</th><th>美图</th></tr>' 
  65.         count = 1 
  66.         for j in mp3Ten: 
  67.             s = f"\n<tr><th>{count}</th><th>{j['singer_name']}</th>" \ 
  68.                 f"<th><a href='{self.get_mp3_url(j['id'])}'>点击播放</a></th><th>{j['album']}</th>" \ 
  69.                 f"<th><img src='{j['image']}'  alt='美图' height='400' width='400' /></th></tr>" 
  70.             content += s            count += 1 
  71.         content += "</table>" 
  72.         return content 
  73.     def sent_email(self, content):        ""
  74.         sent the music demo list for you like one 
  75.         ""
  76.         pwd = keyring.get_password("qqemail""884427640"
  77.         yag = yagmail.SMTP("884427640@qq.com", pwd, host="smtp.qq.com"
  78.         # test qq 2817634007@qq.com 
  79.         yag.send(self.Sented_qq_email, '网易云专属推送', content) 
  80.         yag.close() 
  81.         print("Today music already sent ok!"
  82.     def start_demo(self):        try:            start_name = input("input a music singer or music name " 
  83.                                "if  you like it:"
  84.             id_list = self.get_mp3_id_demo(start=start_name)            self.print_id_list(id_list)            print(self.MUSIC_LIST) 
  85.             self.sent_email(self.random_get_mp3())        except Exception as e:            print("出现error", e, "再试一次!"
  86.             self.start_demo()# 如果要运行此程序 请打开下面的注释# a = DownMp3()# a.start_demo() 

发送邮箱:

  • 函数库用到
  • import keyring
  • import yagmail

下载一下就可以了,

  • 关于keyring 这是一个保存密码的库, 对于一些密码来说,我们可以这样
  • keyring set qq 88442764然后就会让你输入密码 ,当你输入要获得就这样keyring get qq 884427640 就可以了前提你的keyring.exe 在环境变量中, 当然在python中,这个也是很简单使用的。
  • 关于yagmail 这是一个发送邮箱的函数库
  1. def sent_email(self, content): 
  2.        ""
  3.        sent the music demo list for you like one 
  4.        ""
  5.        pwd = keyring.get_password("qqemail""884427640"
  6.        yag = yagmail.SMTP("884427640@qq.com", pwd, host="smtp.qq.com"
  7.        # test qq 2817634007@qq.com 
  8.        yag.send(self.Sented_qq_email, '网易云专属推送', content) 
  9.        yag.close() 
  10.        print("Today music already sent ok!"

pwd 这个是邮箱的QQ邮箱的授权码, 很长的字符串,要去QQ邮箱里面开启服务,所以我就放到密码库里面了,然后用SMTP链接一下邮箱, 就这样发送就可以了。

发送表格:

懂点html的都应该会编写这个。

  1. 就这样写一下就可以了。 
  2. 发送全部代码:# -*- coding :  utf-8 -*- 
  3. # @Time      :  2020/9/17  14:59 
  4. # @author    :  沙漏在下雨# @Software  :  PyCharm# @CSDN      :  https://me.csdn.net/qq_45906219from GetParams import GetParamsimport requestsfrom get_useragent import GetUserAgentCSimport randomimport keyringimport yagmailclass DownMp3(object):    def __init__(self):        self.GetIdUrl = "https://music.163.com/weapi/cloudsearch/get/web?csrf_token=" 
  5.         self.GetMP3Url = 'https://music.163.com/weapi/song/enhance/player/url/v1?csrf_token=' 
  6.         self.ua = GetUserAgentCS().get_user()        self.headers = {"User-Agent": self.ua} 
  7.         self.MUSIC_LIST = []  # The singer music demo list        self.Sented_qq_email = self.get_email()    def get_email(self):        email_list = input("输入QQ邮箱 如果你有多个 请用空格隔开:").split() 
  8.         if len(email_list) == 1: 
  9.             if "@qq.com" not in email_list[0]: 
  10.                 raise Exception("邮箱规格好像不合适,你输入的是 ", email_list[0]) 
  11.             else
  12.                 return email_list[0] 
  13.         elif len(email_list) >= 2: 
  14.             for i in email_list: 
  15.                 if "@qq.com" not in i: 
  16.                     raise Exception("邮箱规格好像不合适,你输入的是 ", i) 
  17.                 else
  18.                     pass            return email_list 
  19.     def my_request(self, url, model="get", params=None): 
  20.         if model == 'post'
  21.             r = requests.post(url, headers=self.headers, params=params)            if r.status_code == 200: 
  22.                 r.encoding = r.apparent_encoding                s = r.json()                return s 
  23.         elif model == 'get'
  24.             r = requests.get(url, headers=self.headers, params=params)            if r.status_code == 200: 
  25.                 return r.content 
  26.         else
  27.             raise Exception("method is error !"
  28.     def get_mp3_id_demo(self, start=None):        ""
  29.         get the mp3 id 
  30.         {"hlpretag":"<span class=\"s-fc7\">","hlposttag":"</span>","s":"本兮","type":"1","offset":"0","total":"true","limit":"30","csrf_token":""
  31.         ""
  32.         if start is None: 
  33.             raise Exception("You should enter a start name, but you enter start =", start) 
  34.         d = { 
  35.             "hlpretag""<span class=\"s-fc7\">"
  36.             "hlposttag""</span>"
  37.             "s": str(start), 
  38.             "type""1"
  39.             "offset""0"
  40.             "total""true"
  41.             "limit""30"
  42.             "csrf_token""" 
  43.         }        params = GetParams().get_encrypt_params(str(d))        return self.my_request(self.GetIdUrl, model="post", params=params)["result"]["songs"
  44.     def get_mp3_url(self, id):        ""
  45.         params: id  the music of id 
  46.         fix  the id into "{"ids":"[35440198]","level":"standard","encodeType":"aac","csrf_token":""}" 
  47.         so we can get the music the downpath 
  48.         ""
  49.         d = {"ids": str([id]), "level""standard""encodeType""aac""csrf_token"""
  50.         params = GetParams().get_encrypt_params(str(d))        context = self.my_request(self.GetMP3Url, model="post", params=params) 
  51.         mp3_path_url = context.get("data")[0]["url"
  52.         return mp3_path_url 
  53.     def print_id_list(self, id_list):        ""
  54.         params: id_list  print the singer about 30s  musics 
  55.         ""
  56.         a = {}        for index, value in enumerate(id_list): 
  57.             a['count'] = (index + 1) 
  58.             a["singer_name"] = value.get("name"
  59.             a["id"] = value.get("id"
  60.             a["album"] = value.get("al").get("name"
  61.             a["image"] = value.get("al").get("picUrl"
  62.             self.MUSIC_LIST.append(a.copy())    def random_get_mp3(self):        mp3Ten = random.sample(self.MUSIC_LIST, 10)  # 提出十首歌 
  63.         content = ""  # 把数据写入html中 方便发送 
  64.         content += '<p><font size="20" color="Tan">Happy day for you !</font></p>' 
  65.         content += '<table border="1" style="border-collapse: collapse;">\n<caption>Today music demo </caption>\n<tr><th>序号</th><th>歌曲名</th><th>歌曲链接</th><th>歌曲所属</th><th>美图</th></tr>' 
  66.         count = 1 
  67.         for j in mp3Ten: 
  68.             s = f"\n<tr><th>{count}</th><th>{j['singer_name']}</th>" \ 
  69.                 f"<th><a href='{self.get_mp3_url(j['id'])}'>点击播放</a></th><th>{j['album']}</th>" \ 
  70.                 f"<th><img src='{j['image']}'  alt='美图' height='400' width='400' /></th></tr>" 
  71.             content += s            count += 1 
  72.         content += "</table>" 
  73.         return content 
  74.     def sent_email(self, content):        ""
  75.         sent the music demo list for you like one 
  76.         ""
  77.         pwd = keyring.get_password("qqemail""884427640"
  78.         yag = yagmail.SMTP("884427640@qq.com", pwd, host="smtp.qq.com"
  79.         # test qq 2817634007@qq.com 
  80.         yag.send(self.Sented_qq_email, '网易云专属推送', content) 
  81.         yag.close() 
  82.         print("Today music already sent ok!"
  83.     def start_demo(self):        try:            start_name = input("input a music singer or music name " 
  84.                                "if  you like it:"
  85.             id_list = self.get_mp3_id_demo(start=start_name)            self.print_id_list(id_list)            print(self.MUSIC_LIST) 
  86.             self.sent_email(self.random_get_mp3())        except Exception as e:            print("出现error", e, "再试一次!"
  87.             self.start_demo()# 如果要运行此程序 请打开下面的注释# a = DownMp3()# a.start_demo()    def random_get_mp3(self):        mp3Ten = random.sample(self.MUSIC_LIST, 10)  # 提出十首歌 
  88.         content = ""  # 把数据写入html中 方便发送 
  89.         content += '<p><font size="20" color="Tan">Happy day for you !</font></p>' 
  90.         content += '<table border="1" style="border-collapse: collapse;">\n<caption>Today music demo </caption>\n<tr><th>序号</th><th>歌曲名</th><th>歌曲链接</th><th>歌曲所属</th><th>美图</th></tr>' 
  91.         count = 1 
  92.         for j in mp3Ten: 
  93.             s = f"\n<tr><th>{count}</th><th>{j['singer_name']}</th>" \ 
  94.                 f"<th><a href='{self.get_mp3_url(j['id'])}'>点击播放</a></th><th>{j['album']}</th>" \ 
  95.                 f"<th><img src='{j['image']}'  alt='美图' height='400' width='400' /></th></tr>" 
  96.             content += s            count += 1 
  97.         content += "</table>" 
  98.         return content 

 

就这样写一下就可以了。

发送全部代码:

 

  1. # -*- coding :  utf-8 -*- 
  2. # @Time      :  2020/9/17  14:59 
  3. # @author    :  沙漏在下雨# @Software  :  PyCharm# @CSDN      :  https://me.csdn.net/qq_45906219from GetParams import GetParamsimport requestsfrom get_useragent import GetUserAgentCSimport randomimport keyringimport yagmailclass DownMp3(object):    def __init__(self):        self.GetIdUrl = "https://music.163.com/weapi/cloudsearch/get/web?csrf_token=" 
  4.         self.GetMP3Url = 'https://music.163.com/weapi/song/enhance/player/url/v1?csrf_token=' 
  5.         self.ua = GetUserAgentCS().get_user()        self.headers = {"User-Agent": self.ua} 
  6.         self.MUSIC_LIST = []  # The singer music demo list        self.Sented_qq_email = self.get_email()    def get_email(self):        email_list = input("输入QQ邮箱 如果你有多个 请用空格隔开:").split() 
  7.         if len(email_list) == 1: 
  8.             if "@qq.com" not in email_list[0]: 
  9.                 raise Exception("邮箱规格好像不合适,你输入的是 ", email_list[0]) 
  10.             else
  11.                 return email_list[0] 
  12.         elif len(email_list) >= 2: 
  13.             for i in email_list: 
  14.                 if "@qq.com" not in i: 
  15.                     raise Exception("邮箱规格好像不合适,你输入的是 ", i) 
  16.                 else
  17.                     pass            return email_list 
  18.     def my_request(self, url, model="get", params=None): 
  19.         if model == 'post'
  20.             r = requests.post(url, headers=self.headers, params=params)            if r.status_code == 200: 
  21.                 r.encoding = r.apparent_encoding                s = r.json()                return s 
  22.         elif model == 'get'
  23.             r = requests.get(url, headers=self.headers, params=params)            if r.status_code == 200: 
  24.                 return r.content 
  25.         else
  26.             raise Exception("method is error !"
  27.     def get_mp3_id_demo(self, start=None):        ""
  28.         get the mp3 id 
  29.         {"hlpretag":"<span class=\"s-fc7\">","hlposttag":"</span>","s":"本兮","type":"1","offset":"0","total":"true","limit":"30","csrf_token":""
  30.         ""
  31.         if start is None: 
  32.             raise Exception("You should enter a start name, but you enter start =", start) 
  33.         d = { 
  34.             "hlpretag""<span class=\"s-fc7\">"
  35.             "hlposttag""</span>"
  36.             "s": str(start), 
  37.             "type""1"
  38.             "offset""0"
  39.             "total""true"
  40.             "limit""30"
  41.             "csrf_token""" 
  42.         }        params = GetParams().get_encrypt_params(str(d))        return self.my_request(self.GetIdUrl, model="post", params=params)["result"]["songs"
  43.     def get_mp3_url(self, id):        ""
  44.         params: id  the music of id 
  45.         fix  the id into "{"ids":"[35440198]","level":"standard","encodeType":"aac","csrf_token":""}" 
  46.         so we can get the music the downpath 
  47.         ""
  48.         d = {"ids": str([id]), "level""standard""encodeType""aac""csrf_token"""
  49.         params = GetParams().get_encrypt_params(str(d))        context = self.my_request(self.GetMP3Url, model="post", params=params) 
  50.         mp3_path_url = context.get("data")[0]["url"
  51.         return mp3_path_url 
  52.     def print_id_list(self, id_list):        ""
  53.         params: id_list  print the singer about 30s  musics 
  54.         ""
  55.         a = {}        for index, value in enumerate(id_list): 
  56.             a['count'] = (index + 1) 
  57.             a["singer_name"] = value.get("name"
  58.             a["id"] = value.get("id"
  59.             a["album"] = value.get("al").get("name"
  60.             a["image"] = value.get("al").get("picUrl"
  61.             self.MUSIC_LIST.append(a.copy())    def random_get_mp3(self):        mp3Ten = random.sample(self.MUSIC_LIST, 10)  # 提出十首歌 
  62.         content = ""  # 把数据写入html中 方便发送 
  63.         content += '<p><font size="20" color="Tan">Happy day for you !</font></p>' 
  64.         content += '<table border="1" style="border-collapse: collapse;">\n<caption>Today music demo </caption>\n<tr><th>序号</th><th>歌曲名</th><th>歌曲链接</th><th>歌曲所属</th><th>美图</th></tr>' 
  65.         count = 1 
  66.         for j in mp3Ten: 
  67.             s = f"\n<tr><th>{count}</th><th>{j['singer_name']}</th>" \ 
  68.                 f"<th><a href='{self.get_mp3_url(j['id'])}'>点击播放</a></th><th>{j['album']}</th>" \ 
  69.                 f"<th><img src='{j['image']}'  alt='美图' height='400' width='400' /></th></tr>" 
  70.             content += s            count += 1 
  71.         content += "</table>" 
  72.         return content 
  73.     def sent_email(self, content):        ""
  74.         sent the music demo list for you like one 
  75.         ""
  76.         pwd = keyring.get_password("qqemail""884427640"
  77.         yag = yagmail.SMTP("884427640@qq.com", pwd, host="smtp.qq.com"
  78.         # test qq 2817634007@qq.com 
  79.         yag.send(self.Sented_qq_email, '网易云专属推送', content) 
  80.         yag.close() 
  81.         print("Today music already sent ok!"
  82.     def start_demo(self):        try:            start_name = input("input a music singer or music name " 
  83.                                "if  you like it:"
  84.             id_list = self.get_mp3_id_demo(start=start_name)            self.print_id_list(id_list)            print(self.MUSIC_LIST) 
  85.             self.sent_email(self.random_get_mp3())        except Exception as e:            print("出现error", e, "再试一次!"
  86.             self.start_demo()# 如果要运行此程序 请打开下面的注释# a = DownMp3()# a.start_demo() 

下载单曲代码:

扩展了一个下载一首歌的代码,如果你需要。

  1. # -*- coding :  utf-8 -*- 
  2. # @Time      :  2020/9/17  21:35 
  3. # @author    :  沙漏在下雨# @Software  :  PyCharm# @CSDN      :  https://me.csdn.net/qq_45906219import requestsfrom get_useragent import GetUserAgentCSfrom GetParams import GetParamsfrom DownMp3 import DownMp3class DownOneMp3(DownMp3):    def __init__(self):        super().__init__()        self.GetIdUrl = "https://music.163.com/weapi/cloudsearch/get/web?csrf_token=" 
  4.         self.params_url = "https://music.163.com/weapi/song/enhance/player/url/v1?csrf_token=" 
  5.         self.headers = {"user-agent": GetUserAgentCS().get_user()} 
  6.         self.start = input("Please input the music name:"
  7.         ids = self.get_id()        self.params = self.get_params(id=ids)        self.mp3_name = self.start + ".mp3" 
  8.     def my_request(self, url, model="get", params=None): 
  9.         ""
  10.         继承父类的一个方法 
  11.         ""
  12.         return super().my_request(url, model, params) 
  13.     def get_params(self, id):        """给出id 返回加密参数""" 
  14.         d = {"ids": str([id]), "level""standard""encodeType""aac""csrf_token"""
  15.         params = GetParams().get_encrypt_params(str(d))        return params 
  16.     def get_id(self):        ""
  17.         根据歌曲名称获取id 
  18.         ""
  19.         start = self.start        d = {            "hlpretag""<span class=\"s-fc7\">"
  20.             "hlposttag""</span>"
  21.             "s": str(start), 
  22.             "type""1"
  23.             "offset""0"
  24.             "total""true"
  25.             "limit""30"
  26.             "csrf_token""" 
  27.         }        params = GetParams().get_encrypt_params(str(d))        return self.my_request(self.GetIdUrl, model="post", params=params)["result"]["songs"][0].get("id"
  28.     def spider(self):        ""
  29.         这是爬取一首歌的方式, 你只需要输入歌曲名称就可以 会自动调用其他类实现参数加密 id获取等 
  30.         ""
  31.         import os 
  32.         r = requests.post(self.params_url, params=self.params)        if r.status_code == 200: 
  33.             print(r.json()) 
  34.             mp3 = r.json().get("data")[0].get("url"
  35.             print("music link is ", mp3) 
  36.             rmp3 = requests.get(mp3, headers=self.headers)            if rmp3.status_code == 200: 
  37.                 with open(self.mp3_name, 'wb'as ;fw:&nbsp;
  38.                     ;fw.write(rmp3.content) 
  39.                 print("Down Successful! ""file path is ", os.path.dirname(__file__)) 
  40. # 如果要运行此程序 请打开下面的注释# a = DownOneMp3()# a.spider() 

关于__init__ :

  1. ""
  2. 如果你仅仅只是想下载一首歌 跳转到DownOneMp3模块启动模块运行 
  3. 如果你想多首歌发送某人邮箱  跳转到DownMp3模块启动模块运行 
  4. ""

JS逆向, ASE加密, RES非对称算法,yagmail邮箱的发送,浏览器的debug,学到就是爽。

到这里就结束啦。此文转载于:沙漏在下雨,著作权归作者所有,如有侵权联系小编删除!

责任编辑:未丽燕 来源: 今日头条
相关推荐

2011-11-01 16:51:07

网易邮箱

2022-02-09 10:32:19

jsrpcjsrpc工具网络爬虫

2021-05-13 08:11:50

网易批量音乐

2011-12-08 16:02:35

K歌达人

2012-04-16 18:08:02

网易邮箱

2023-01-03 17:43:39

网易邮箱数仓

2012-05-25 13:54:18

JavaScript

2015-10-19 18:16:15

2014-11-13 16:43:45

网易邮箱

2013-04-03 14:25:36

网易邮箱

2022-04-06 09:02:58

JS反编译App

2015-10-20 23:52:32

数据泄露网易邮箱

2015-01-13 12:31:26

邮箱用户行为报告

2015-10-19 18:18:44

2012-06-27 17:38:05

网易邮箱

2013-12-26 14:09:23

2010-07-05 21:49:27

2015-01-14 10:11:29

邮箱用户行为移动办公

2018-05-14 14:02:41

Python爬虫网易云音乐

2022-05-26 12:26:27

CSSJS逆向
点赞
收藏

51CTO技术栈公众号