# -*- 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()