日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

网易云音乐JS逆向

發布時間:2023/12/9 javascript 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 网易云音乐JS逆向 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

手把手教你網易云音樂JS逆向

1. 目標數據

  • 1.搜索音樂,獲取音樂id
  • 2.獲取url,下載音樂

2. 文章目錄

目錄

    • 手把手教你網易云音樂JS逆向
    • 1. 目標數據
    • 2. 文章目錄
    • 3. 頁面分析
    • 4. 模擬加密,獲取參數
    • 5.獲取url,下載音樂
    • 6. 歌曲搜索
      • 完美收工~~~
      • [下一篇 打造網易云圖形界面](https://blog.csdn.net/zly717216/article/details/113548197)

3. 頁面分析

用chrome瀏覽器進入網易云音樂官網,找到一首你喜歡的歌

進入歌曲頁面后,url中有一個參數id,因此可以猜想:如果當前頁面中能找到歌曲的url,只需要用id構造url,就能獲取歌曲的鏈接,但事實上沒有那么簡單(后面會詳細分析)

按F12 ,打開調試面板,刷新。發現,當前頁面是一個html頁面

搜索歌曲id,但是網頁源代碼中并沒有(所以前面的猜想不成立,得另尋他法)
既然這樣,歌曲可能是動態加載的,需要到js中找,點擊 XHR,從第一個到最后一個連接,發現并沒有當前頁面的id(1398663411)

既然是動態加載,再點擊播放試試。功夫不負有心人,果然找到了

既然找到了,那就打開看看它的廬山站面目,看到url,并且是m4a后綴,是不是很驚喜

果然沒錯,就是它

既然這樣我們就試試吧,結果發現,能拿到數據

import requestsurl = 'https://music.163.com/weapi/song/enhance/player/url/v1?csrf_token=' headers = {'origin': 'https://music.163.com','referer': 'https://music.163.com/','user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36' } data = {'params': '+i3P/nsviot5Ms6bDX+wUmyKAFRm7u3J7pdECwtbeVV10k41za7DjYIXSgCbNngYOO7GH+ADMz/pULLM6bItfAGGfjatL9xirPAWnwzGbr9uTul31ITnC9es8lu01n5eyP8svVHDCecGH57SU0u+hA==','encSecKey': '21c157c5c208498782f0cecee8b518ee8726bba93e2dcb6e280d4d0e4c6ceea3107e5eaab6ad55ca53c713cd9893d5cf11491dae043bebccacc1c95680fff17ba34ccdfc3e3c4863eca69b671ef510a44e3f68d6fc182222d6e55b6d0fa320bf166364c82aa6a2adb641d60e7f480d5809f9c7e1963f884c9c5cf80cd81e5e08' }res = requests.post(url, headers=headers, data=data) print(res.json())


但是問題來了,params和encSeckey是啥玩意兒?這么長,一看就知道是加過密的,接下來要開啟解密模式了
點擊面板右上角的全局搜索,搜索encSeckey

有3個js文件,一個一個去找吧

先別著急找,像下面這樣,結合起來,在第一個js文件中找到的可能性大一些,既然這樣,那就開始找吧

小插曲:上面為什要搜encSeckey,而不搜params呢?因為用params命名的使用范圍要比encSeckey廣,所以用encSeckey搜好一些(經驗)

點擊第一個js,進去后點擊格式化,搜索encSeckey,發現有3處,
滑到第二處,為什么是第二處呢?很簡單,因為params和encSeckey在一起嘛,不在這你說在哪?好了,到這里,另外的兩個js可以忽略了。

接下來就要分析參數了,我們往上嫖,發現兩個參數分別是由bWv7o的encText、encSecKey兩個屬性。

接下來才是真正的js逆向了,敲黑板了!!!

既然params和encKeckey是由bWv7o產生的,那么我們就要分析bWv7o是什么了。不難發現bWv7o是由window.asrsea(JSON.stringify(i1x), bsK8C(["流淚", "強"]), bsK8C(XR1x.md), bsK8C(["愛心", "女孩", "驚恐", "大笑"]));產生的,那么接下來就找找window.asrsea是啥玩意兒

搜索一下window.asrsea,window.asrsea=d

這里d就不能去搜索了,不現實,原因你懂的。這里的d肯定是和window.asrsea在同一作用域內,要不然咋賦值,稀里嘩啦寶一大堆錯,既然這樣就往上翻吧(因為是賦值,所以不會在下面,沒人這么干)

在同一作用域內的就這么點,就一個d函數

!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}window.asrsea = d,window.ecnonasr = e }();

接下來分析d函數是干嘛的,看來看去該函數不就返歸一個h對象嘛,不就相當于window.asrsea=h嘛,而params就是encText ,encSecKey 就是encSecKey;encText 是b(h.encText, i)產生的,encSecKey是由c(i, e, f)產生的,接下來打上斷點,開始調試吧

刷新,點擊播放,發現有4個參數



再點一首歌,發現e,f,g三個參數是固定的

綜上,d參數是變化的,而且變化的地方是id,分析的時候就當它是固定的,接著往后走

h={},i=a(16),那么a(16)是什么?點擊去,一探究竟


經過調試和分析,a函數返回一個16位隨機字符串(既然是隨機的,那么就可以讓它固定)


接著往后走
由此可見b函數,是用來加密的,而且是encText經過了兩次加密,跳進去,看看這個加密函數

原來是AES加密,熟悉AES的,肯定敲開心,不熟悉也沒關系,很容易

function b(a, b) { // urf-8編碼var c = CryptoJS.enc.Utf8.parse(b), d = CryptoJS.enc.Utf8.parse("0102030405060708") // 固定值, e = CryptoJS.enc.Utf8.parse(a)// AES加密,e加密文本,c秘鑰,d偏移量,CBC模式, f = CryptoJS.AES.encrypt(e, c, {iv: d,mode: CryptoJS.mode.CBC});return f.toString()}

接下來分析encSecKey參數,跳入到c函數,長這樣

function c(a, b, c) { // a,b,c是固定值var d, e;return setMaxDigits(131), // 跳進去,調試... 創建長度為132的數組d = new RSAKeyPair(b,"",c), // e = encryptedString(d, a)}

由此可知,encSeckey是經過RSA加密的,但是這里的a,b,c三個參數是固定值,因此這個參數也可以用固定值

好了,到這里js逆向分析就結束了

4. 模擬加密,獲取參數

class Encrypt:def __init__(self, text):self.data = {'encSecKey': '01ec48cb405730aa77f993a988cc1f5bc1938511d75f49eddc581f2fe2aaf18988853200564b2d4b1312cf6e0bb344425addce5a4c81b38b89a5973900946bd100b0f1865d22d2a8e5dd8be208eb5d6eb2f71309a165daeffe95355e1e44edd65bdf28088fe4f5e835a7d9f7569fc2530f9d17c00b51cfafbe421eb462247ea3'}self.text = textself.key = '0CoJUm6Qyw8W8jud'def get_form_data(self):"""生成表單參數"""# 隨機秘鑰參數,可以用固定值i = "4JknCzx6uEXUwxpU"# 兩次加密first_encrypt = self.AES_encpyt(self.text, self.key)self.data['params'] = self.AES_encpyt(first_encrypt, i)return self.datadef AES_encpyt(self, text, key):"""AES加密"""# AES加密明文必須為16的整數倍padding = 16 - len(text.encode()) % 16text += padding * chr(padding)aes = AES.new(key.encode(), AES.MODE_CBC, b'0102030405060708')enctext = aes.encrypt(text.encode())return b64encode(enctext).decode('utf-8')

5.獲取url,下載音樂

class NeteaseCloudMusic:def __init__(self, song):self.url = 'https://music.163.com/weapi/song/enhance/player/url/v1?csrf_token='reqstr = '''authority: music.163.commethod: POSTpath: /weapi/song/enhance/player/url/v1?csrf_token=scheme: httpsaccept: */*accept-encoding: gzip, deflate, braccept-language: zh-CN,zh;q=0.9cache-control: no-cachecontent-length: 434content-type: application/x-www-form-urlencodedcookie: __root_domain_v=.163.com; _qddaz=QD.28yaab.3jymc6.kf0ihnaf; _ntes_nnid=e7c5f90265b4d5a5bcb511efebf7a890,1600596980395; _ntes_nuid=e7c5f90265b4d5a5bcb511efebf7a890; _iuqxldmzr_=32; WM_TID=OlHvFOuIVclAQFQUAEJvJZyLuh3MwtGb; NMTID=00ODCot1Uq8CvcXIUIMmKBlPfRiyfoAAAF3NHwibw; WM_NI=%2BWiHzgkFWg%2BON3YYI0rQzlpsOW8x4BPGt%2FWRNpkD3r2Utv8U1gx6RZgvmmJQ0IpSBgdk1GvY9uIQW6BfIN7lVoHo8z1BIoa%2FdLUgKwpx6twUKJtgDlexKOu7LqWGuYApZzg%3D; WM_NIKE=9ca17ae2e6ffcda170e2e6eeb9c844a3b1aba3b24489eb8eb6d15b929a9baaaa5cace70087b64e8ab18299d02af0fea7c3b92ae989a7a9f96da99a9988aa458eed97bacc3cb28fb68df3798d89f899b74a9499bcd0d65a8eb0a5a5b27af28bbc97bb5ff3b9b8d7d152a5aaa38ec95bf497c0b4c16da8b5ffa8f553fbab87b2d63e82ba87afb66896b18890bb72f39e8790e425a8949b88ca7db4a8fa95f65f8996bc88c768a7a885b0f83d90af99a8f85383b0969be637e2a3; hb_MA-9F44-2FC2BD04228F_source=www.baidu.com; JSESSIONID-WYYY=bERBG86BVbD29X%5C35acjg8ndIoGYPEZvQ8fc0t7WUnMu3KTujvG1zqfSMIG%2By4%2FZRz9hC%2FwBN0Mf%2B%2B1RJBK2TeR96X7l%2BmS%2FHhuuqBwl7yxwe4jQ%5ChzFoFgKylb3ZdOnw6%2FqsqaUYUrJ12EVVy0m66JVlQez0T5ijmgZuOsk0KcMnUe4%3A1611553513123; WEVNSM=1.0.0; WNMCID=kctjbv.1611551714155.01.0origin: https://music.163.compragma: no-cachereferer: https://music.163.com/sec-fetch-dest: emptysec-fetch-mode: corssec-fetch-site: same-originuser-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36'''self.headers = HeaderPrettyDict().pretty(reqstr)self.text = '{"ids":"[' + str(song['song_id']) + ']","level":"standard","encodeType":"aac","csrf_token":""}'self.name = song['song_name']self.singer = song['singer']def music(self):"""獲取音樂的url"""data = Encrypt(self.text).get_form_data()res = requests.post(self.url, headers=self.headers, data=data)song_url = res.json()['data'][0]['url']self.save(self.download(song_url))def download(self, url):"""下載音樂"""headers = {'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36'}res = requests.get(url, headers=headers)return res.contentdef save(self, content):"""保存音樂"""# 當前文件目錄path = os.path.dirname(__file__)# 檢查'data'目錄是否存在,不存在則創建目錄if not os.path.exists(path+'\\data'):os.mkdir(path+'\\data')# 音樂保存路徑music_path = path+'\\data'+f'\\{self.name} {self.singer}.m4a'# 保存if not os.path.exists(music_path):with open(music_path, 'wb') as f:f.write(content)

6. 歌曲搜索

以上只能實現單曲下載,下面將實現歌曲搜索功能

先分析一下url的結構:url有連個參數,一個是s(歌曲名),一個是type(類型:單曲、視頻、歌詞等)

type類型總結如下:

數字類型
1單曲
10專輯
100歌手
1014視頻
1006歌詞
1000歌單
1009聲音主播
1002用戶

步驟和前面一樣,先找到數據來源

接下來就要分析請求網址和參數了,乍一看,和前面一模一樣啊

開心吧!!!但是事與愿違,雖然參數一樣,但是用前面的生成參數卻無法get到數據,別慌,方法還是一樣,斷點調試

經過調試之后,我們發現就是d參數不同(d={"hlpretag":"<span class=\"s-fc7\">","hlposttag":"</span>","s":"冬眠","type":"1","offset":"0","total":"true","limit":"30","csrf_token":""}),因此只要構造d參數就能請求到數據了


直接上代碼吧

class SearchMusic:def __init__(self, text):self.url = 'https://music.163.com/weapi/cloudsearch/get/web?csrf_token='reqstr = '''authority: music.163.commethod: POSTpath: /weapi/song/enhance/player/url/v1?csrf_token=scheme: httpsaccept: */*accept-encoding: gzip, deflate, braccept-language: zh-CN,zh;q=0.9cache-control: no-cachecontent-length: 434content-type: application/x-www-form-urlencodedcookie: __root_domain_v=.163.com; _qddaz=QD.28yaab.3jymc6.kf0ihnaf; _ntes_nnid=e7c5f90265b4d5a5bcb511efebf7a890,1600596980395; _ntes_nuid=e7c5f90265b4d5a5bcb511efebf7a890; _iuqxldmzr_=32; WM_TID=OlHvFOuIVclAQFQUAEJvJZyLuh3MwtGb; NMTID=00ODCot1Uq8CvcXIUIMmKBlPfRiyfoAAAF3NHwibw; WM_NI=%2BWiHzgkFWg%2BON3YYI0rQzlpsOW8x4BPGt%2FWRNpkD3r2Utv8U1gx6RZgvmmJQ0IpSBgdk1GvY9uIQW6BfIN7lVoHo8z1BIoa%2FdLUgKwpx6twUKJtgDlexKOu7LqWGuYApZzg%3D; WM_NIKE=9ca17ae2e6ffcda170e2e6eeb9c844a3b1aba3b24489eb8eb6d15b929a9baaaa5cace70087b64e8ab18299d02af0fea7c3b92ae989a7a9f96da99a9988aa458eed97bacc3cb28fb68df3798d89f899b74a9499bcd0d65a8eb0a5a5b27af28bbc97bb5ff3b9b8d7d152a5aaa38ec95bf497c0b4c16da8b5ffa8f553fbab87b2d63e82ba87afb66896b18890bb72f39e8790e425a8949b88ca7db4a8fa95f65f8996bc88c768a7a885b0f83d90af99a8f85383b0969be637e2a3; hb_MA-9F44-2FC2BD04228F_source=www.baidu.com; JSESSIONID-WYYY=bERBG86BVbD29X%5C35acjg8ndIoGYPEZvQ8fc0t7WUnMu3KTujvG1zqfSMIG%2By4%2FZRz9hC%2FwBN0Mf%2B%2B1RJBK2TeR96X7l%2BmS%2FHhuuqBwl7yxwe4jQ%5ChzFoFgKylb3ZdOnw6%2FqsqaUYUrJ12EVVy0m66JVlQez0T5ijmgZuOsk0KcMnUe4%3A1611553513123; WEVNSM=1.0.0; WNMCID=kctjbv.1611551714155.01.0origin: https://music.163.compragma: no-cachereferer: https://music.163.com/sec-fetch-dest: emptysec-fetch-mode: corssec-fetch-site: same-originuser-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36'''self.headers = HeaderPrettyDict().pretty(reqstr)self.text = textdef search(self):"""搜索音樂,返回音樂列表"""data = Encrypt(self.text).get_form_data()res = requests.post(self.url, headers=self.headers, data=data)songlist = []songs = res.json()['result']['songs']for song in songs:item = {}# id、歌名、歌手、封面item['song_id'] = song['id']item['song_name'] = song['name']item['singer'] = song['ar'][0]['name']# item['song_pic_url'] = song['al']['picUrl']songlist.append(item)return songlist

完美收工~~~

下一篇 打造網易云圖形界面

總結

以上是生活随笔為你收集整理的网易云音乐JS逆向的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。