# -*- coding: utf-8 -*-
from Crypto.Cipher import AES
import base64
import random
import codecs
import requests
from fake_useragent import UserAgent
from http.cookiejar import LWPCookieJar
import hashlib
'''
之前也寫過網易雲音樂的評論爬取,下載歌曲,還有其他等等。。。
網易雲音樂登錄加密方式其實和評論的加密方式是一樣的,只不過傳入的參數不同罷了,而登錄需要構造下面login方法注釋里字典格式
注意千萬不要使用json.dumps(字典)來將字典轉為json格式字符串。因為字典它是無序的,轉出來的json字符串有可能是不一樣的,這樣
導致最終加密出來的字符串是不同的
其實上一篇爬取評論的時候,我就寫了登錄方式。但是登錄失敗了。加密方式是沒有變的,通過js調試,我發現checkToken這個參數的值,
它是變化的,所以那時就一直想找到checkToken它的參數是怎么來的。找得頭都大,位置大概知道了。但是解出來的話,我能力不夠(其實就不太願意花時間去弄),
我也在網上搜索過,但也沒找到想要的答案。弄了一段時間,就先放一放了。
昨天晚上寫完微博的模擬登錄,今早想起了網易雲音樂登錄還沒寫完。搗騰了一會兒。發現之前一直想解出的checkToken參數,不傳也
可以成功登錄。
不必要弄懂全部參數的加密方式,有時候這個參數后台不是判斷的必要條件。
'''
class WYY:
ua = UserAgent()
def __init__(self):
self.arg2 = "010001"
self.arg3 = "00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7b725152b3ab17a876aea8a5aa76d2e417629ec4ee341f56135fccf695280104e0312ecbda92557c93870114af6c9d05c4f7f0c3685b7a46bee255932575cce10b424d813cfe4875d3e82047b97ddef52741d546b8e289dc6935b3ece0462db0a22b8e7"
self.arg4 = "0CoJUm6Qyw8W8jud"
self.session = requests.Session()
self.session.headers = {
"Referer": "https://music.163.com/",
"User-Agent": self.ua.random
}
self.session.cookies = LWPCookieJar(filename="./cookie.txt")
self.__get_random_str()
def __AES_encrypt(self, text, key):
'''
獲取到加密后的數據
:param text: 首先CBC加密方法,text必須位16位數據
:param key: 加密的key
:return: 加密后的字符串
'''
iv = "0102030405060708"
pad = 16 - len(text) % 16
if isinstance(text, str):
text = text + pad * chr(pad)
else:
text = text.deocde("utf-8") + pad * chr(pad)
aes = AES.new(key=bytes(key, encoding="utf-8"), mode=2, iv=bytes(iv, encoding="utf-8"))
res = aes.encrypt(bytes(text, encoding="utf-8"))
res = base64.b64encode(res).decode("utf-8")
return res
def __get_encText(self, args1):
encText = self.__AES_encrypt(args1, self.arg4)
encText = self.__AES_encrypt(encText, self.random_16_str)
return encText
def __get_encSecKey(self):
'''通過查看js代碼,獲取encSecKey'''
text = self.random_16_str[::-1]
rs = int(codecs.encode(text.encode('utf-8'), 'hex_codec'), 16) ** int(self.arg2, 16) % int(self.arg3, 16)
return format(rs, 'x').zfill(256)
def __get_random_str(self):
'''這是16位的隨機字符串'''
str_set = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
random_str = ""
for i in range(16):
index = random.randint(0, len(str_set) - 1)
random_str += str_set[index]
self.random_16_str = random_str
def __getFormData(self, args1):
'''獲取到提交的數據'''
data = {"params": self.__get_encText(args1), "encSecKey": self.__get_encSecKey()}
return data
def login(self, username: str = None, password: str = None):
'''網易雲登錄'''
'''
參數一為構造這樣的字典格式
checkToken: "9ca17ae2e6ffcda170e2e6eed9ee33fb9d9dd6cb7a98ef8eb2d85b879b9ababc6788b6ab96f95afcb8adaabc2af0feaec3b92aadb88ab1c446a1ef0099f65a879f9ba6c85a9bb0a2b9e945f5eca69bd952af95ee9e"
csrf_token: ""
password: "5cf36a0d72feb44111716322921ed011"
phone: "18716758271"
rememberLogin: "true"
'''
api = "https://music.163.com/weapi/login/cellphone?csrf_token="
headers = {}
headers["content-type"] = "application/x-www-form-urlencoded"
headers["user-agent"] = self.ua.random
headers["referer"] = "https://music.163.com/"
if not username:
username = input("輸入你的電話>>:").strip()
else:
username = username.strip()
if not password:
password = input("輸入你的密碼>>:").strip()
else:
password = password.strip()
self.arg1_login = '{"phone":"%s","password":"%s","rememberLogin":"true","checkToken":"","csrf_token": ""}' % (
username, hashlib.md5(bytes(password, encoding="utf-8")).hexdigest())
formdata = self.__getFormData(self.arg1_login)
response = self.session.post(url=api, headers=headers, data=formdata)
results = response.json()
if results["code"] == 200:
self.session.cookies.save()
print("登錄成功")
else:
print(results["msg"])
def text(self):
'''測試方式'''
pass
if __name__ == '__main__':
wyy = WYY()
wyy.login()