Python实现网易云音乐歌曲URL获取攻略
获取歌曲url链接需要知道音乐的id,获取id的方式有很多,像歌单,排行榜等可以直接获得。下面是针对网页版搜索栏,通过歌曲名字获取对应的歌曲id(注:本文代码不全,只列出大概)
import json
import requests,random
import base64
from Crypto.Cipher import AES
import pandas as pd
import math
def set_user_agent():
USER_AGENTS = [
"Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0; .NET CLR 3.5.30729; .NET CLR 3.0.30729; .NET CLR 2.0.50727; Media Center PC 6.0)",
"Mozilla/5.0 (compatible; MSIE 8.0; Windows NT 6.0; Trident/4.0; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; .NET CLR 1.0.3705; .NET CLR 1.1.4322)",
"Mozilla/4.0 (compatible; MSIE 7.0b; Windows NT 5.2; .NET CLR 1.1.4322; .NET CLR 2.0.50727; InfoPath.2; .NET CLR 3.0.04506.30)",
"Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN) AppleWebKit/523.15 (KHTML, like Gecko, Safari/419.3) Arora/0.3 (Change: 287 c9dfb30)",
"Mozilla/5.0 (X11; U; Linux; en-US) AppleWebKit/527+ (KHTML, like Gecko, Safari/419.3) Arora/0.6",
"Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.2pre) Gecko/20070215 K-Ninja/2.1.1",
"Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9) Gecko/20080705 Firefox/3.0 Kapiko/3.0",
"Mozilla/5.0 (X11; Linux i686; U;) Gecko/20070322 Kazehakase/0.4.5",
]
user_agent = random.choice(USER_AGENTS)
return user_agent
def getsonglist(name):
c_json ={"hlpretag":"<span class=\"s-fc7\">",
"hlposttag":"</span>",
"s":name,
"type":"1", #true
"offset":"0",
"total":"true",
"limit":"10",
"csrf_token":"05594195875"}
c_json=json.dumps(c_json)
huoqu=getdata(c_json)
encSecKey=huoqu.getencSecKey()
encText=huoqu.getencText()
url='https://music.163.com/weapi/cloudsearch/get/web?csrf_token=05594195875'
hd={
'cookie': 'MUSIC_U=00C0B2C6EC5E96F308AB1C35FC07C3EC3637FB71E35A003A2E5494B9AA35A56BED4184C398FA9EE283E9FDBF6EC7B8460C7FF7AA244AAB03636D1EB0D055B1E8ED58EEA5EE4FE48C56CAD7FED09B9E90098E819233229F4B0DE4D36CCBB1DB03F219D00FDA3DA60B9B8A23014317B7F286AE9B9D8F3F2DF8B5CA52F5057F6E0789B819167FB2BEF2529EC004CF1498EC0AB5A854CA97C3C29D4BCB83C0C7CB2B9EAF4AB4E33353AB4500E9BD3981DA9848BA18AF0B9621733227F54B1E580FCA87EDB86BBAD24EE8D1BCCB1066F76D9F6D4BAF0320CBF1AF7E21BDD74ACB6706D970B4A867663CE53AC9EBD0834F5DB4F8FF8AD0A8D27F5ED6DE980481DDB8D42BB3612A5B21532C92CE1A6FF7813C03A4DCC8474334272736E1F7538558C5BFB7515F8FF62151F34342E94DFB061701B95A0307F506F68BACCD7571E9EE819BE713E225159AAD07A5752D8D16DB7D7377A2EDB8AACAE9FC773BED4D5B4C7DA37E5D18AE5782146D1E1A206C55C34DAE0E',
'Accept': '*/*',
'Accept-Encoding': 'gzip,deflate,sdch',
'Accept-Language': 'zh-CN,zh;q=0.8,gl;q=0.6,zh-TW;q=0.4',
'Connection': 'keep-alive',
'Content-Type': 'application/x-www-form-urlencoded',
'Host': 'music.163.com',
'Referer': 'https://music.163.com/search/',
'User-Agent': set_user_agent()
}
da={
'params':encText,
'encSecKey':encSecKey
}
res=requests.post(url,data=da,headers=hd).json()
song_data=res['result']['songs']
songname=[]
songid=[]
singer=[]
for song in song_data:
songname.append(song['name'])
singer.append(song['ar'][0]['name'])
songid.append(song['id'])
df = pd.DataFrame(
data={
'歌曲名称':songname,
'歌手': singer
}
)
print(df)
n=int(input("请选择歌曲:"))
z={'歌曲':songname[n],'歌手':singer[n],'歌曲id':songid[n]}
return z
if __name__ == '__main__':
name=input("请输入歌曲名称")
print(getsonglist(name))
上述中的参数需要改变例如MUSIC_U(需要用户登录,在Cookie中找,一般是在靠后的位置),MUSIC_U会过期。params和encSecKey参数是在页面上进行的加密,可以找寻
通过断点追踪可以找到大概是这里,其中详细的加密过程可以继续打断点看,这里就不多说了。大概其中一个是经过两轮的AES加密,另外一个是RSA加密,可以通过Python的第三方库进行加密。参考代码如下
def pkcs7(a):
length = len(a.encode('utf-8'))
count = 16 - length % 16
tianchong = count * chr(count)
return a + tianchong
class aesjiami:
def __init__(self,key): #key="0CoJUm6Qyw8W8jud" "0CoJUm6Qyw8W8jud"
self.key=key.encode('utf-8') #密钥
self.iv="0102030405060708".encode('utf-8') #初始向量
def aes(self,text):
self.text=pkcs7(text) #数据填充为16的整数倍
Aes=AES.new(self.key, AES.MODE_CBC, self.iv) #密钥,模式,偏移量
miwen=Aes.encrypt(self.text.encode('utf-8')) #加密
result=str(base64.b64encode(miwen), encoding='utf-8') #64编码
return result
class rsajiami: #setMaxDigits(131)设置大数的最大位数为131
def __init__(self):
self.s="nihao"
def RSAEncrypt(self, i, e, n):
num = pow(int(i[::-1].encode().hex(), 16), int(e, 16), int(n, 16))
result = format(num, 'x')
return result
def a (a): #随机生成16位随机字符
b = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" #62个初始字符
c = ""
for d in range(a):
e=random.random()*len(b)
e=math.floor(e) #取不超过当前大小的最大整数 该数值不大于61且不小于0
s=int(e)
c+=b[s] #根据值去下标对应的字符返回
return c
运行结果示例:
获取歌曲后通过ID获取url链接,其中也涉及了两个参数加密,一个Cookie反爬(MUSIC_U,针对不许要VIP的歌曲无需正确,有即可;针对VIP歌曲需要是VIP用户的MUSIC_U),和上面类似,代码如下
import sys
import json
import requests,random
import base64
from Crypto.Cipher import AES
import math
import 网易云获取歌曲信息
#凄美地 436346833 达尔文 2019573476
def pkcs7(a):
length = len(a.encode('utf-8'))
count = 16 - length % 16
tianchong = count * chr(count)
return a + tianchong
class aesjiami:
def __init__(self,key): #key="0CoJUm6Qyw8W8jud" "0CoJUm6Qyw8W8jud"
self.key=key.encode('utf-8') #密钥
self.iv="0102030405060708".encode('utf-8') #初始向量
def aes(self,text):
self.text=pkcs7(text) #数据填充为16的整数倍
Aes=AES.new(self.key, AES.MODE_CBC, self.iv) #密钥,模式,偏移量
miwen=Aes.encrypt(self.text.encode('utf-8')) #加密
result=str(base64.b64encode(miwen), encoding='utf-8') #64编码
return result
class rsajiami: #setMaxDigits(131)设置大数的最大位数为131
def __init__(self):
self.s="nihao"
def RSAEncrypt(self, i, e, n):
num = pow(int(i[::-1].encode().hex(), 16), int(e, 16), int(n, 16))
result = format(num, 'x')
return result
def a (a): #随机生成16位随机字符
b = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" #62个初始字符
c = ""
for d in range(a):
e=random.random()*len(b)
e=math.floor(e) #取不超过当前大小的最大整数 该数值不大于61且不小于0
s=int(e)
c+=b[s] #根据值去下标对应的字符返回
return c
class getdata:
def __init__(self,token):
self.token=token
self.sandom=a(16)
self.g="00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7b725152b3ab17a876aea8a5aa76d2e417629ec4ee341f56135fccf695280104e0312ecbda92557c93870114af6c9d05c4f7f0c3685b7a46bee255932575cce10b424d813cfe4875d3e82047b97ddef52741d546b8e289dc6935b3ece0462db0a22b8e7"
def getencText(self):
a=aesjiami("0CoJUm6Qyw8W8jud")
#s=a.aes(json.dumps(self.token,separators=(',', ':'))) 去除空格
s=a.aes(self.token)
x=aesjiami(self.sandom)
y=x.aes(s)
return y+'='
def getencSecKey(self):
b = rsajiami()
rs = b.RSAEncrypt(self.sandom,"010001",self.g)
return rs
def fin(songname):
url='https://music.163.com/weapi/song/enhance/player/url/v1?csrf_token='
hd={
'cookie':'MUSIC_U=00D9E5A701C4CBE2208D2D66D740371C4B670703CD68AEA25EF7DE1A4350A9AC75AA967DA9295B928AA257B9A6B559E3CCC516E962993D0B44BAD876F094523089A003BDF55CF829AF25E2EAED2E54FDC90C93E0ECC5B85A7DBFC62B4FDF644ACCF61814FB1950665873C599937E5B8F6860883677CD9A6D74D8433CBA7AD195773F68B4796E3C623433B3B8934EA8D2A0948E26A142D850CC8A969D191B077BB2B4BFBDB5C1C991B0F48AB978433FA734E5BBC6E1CE1F9B136F667AE1B967F4B058133D5FA6D78A5B1B5D7A95B7421FBEFD811E6051F0409D104554D630D519346A3C5DF9BBFB926015AFE0CF6FDB667C111C294527E80465F08323D5841351E42B79792FD083B3BA98FC62148EF92E94F91A4EEDD12C25AEEB9F8E744C04FCBEA8F06C29C24CAF58904C7E83FDE7546944B96BAEA14C19CF1120F2C63A6D50C2BF5C3812D1754A4362761013C7FFE54B031FCF163AA5154AD6ADBF375B4B0F53D2EE4ED4D3EFCFC5755F8DBEEB797EC8',
'path':'/weapi/song/enhance/player/url/v1?csrf_token=bc9fe810560f94e43faa84bb9128830c',
'Accept': '*/*',
'Accept-Encoding': 'gzip,deflate,sdch',
'Accept-Language': 'zh-CN,zh;q=0.8,gl;q=0.6,zh-TW;q=0.4',
'Connection': 'keep-alive',
'Content-Type': 'application/x-www-form-urlencoded',
'Host': 'music.163.com',
'Referer': 'https://music.163.com/search/',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36 Edg/115.0.1901.188'
}
c_json = {"ids":"[25727803]","level":"standard","encodeType":"aac","csrf_token":"05594195875be0ea6afd6d377c24a98e"}
c_json['ids'] = '[' + songname + ']'
c_json = json.dumps(c_json)
huoqu = getdata(c_json)
encSecKey = huoqu.getencSecKey()
encText = huoqu.getencText()
da={
'params':encText,
'encSecKey':encSecKey
}
res=requests.post(url,data=da,headers=hd).text
data = json.loads(res)['data']
finurl=data[0]["url"]
s = finurl.split('?')[0]
print(s)
return s
if __name__ == '__main__':
fin('442867218')
作者:成为一个句号