1. 程式人生 > >Python 網易雲音樂評論爬蟲

Python 網易雲音樂評論爬蟲

引言

之前網易雲音樂和農夫山泉合作,將熱門評論印在農夫山泉上引爆了朋友圈。於是想爬取一下網易雲的評論。網上搜了一下,對於網易雲評論的爬蟲不少,主要參考這篇文章:對網易雲音樂引數(params,encSecKey)的分析 。在此基礎上,添加了爬取雲音樂飆升榜中歌曲,再去爬取這些歌曲的評論。在做專案的過程中還是遇到了一些問題,在此記錄下來

思路

  1. 爬取雲音樂飆升榜中的歌曲相關資訊
  2. 爬取對應歌曲的熱門評論
  3. 爬取對應歌曲的前20條最新評論

問題

1. 雲音樂飆升榜中歌曲資訊是JS動態生成,直接爬取拿不到

最開始是想從介面上爬取資料,但是發現榜單歌曲是JS動態生成的,需要分析JS程式碼後才能獲取。Google後發現網易雲有提供現成的介面api,直接可以用,返回的是JSON格式資料,省去分析JS的過程了。

# 排行榜api,本專案爬取雲音樂飆升榜
# http://music.163.com/api/playlist/detail?id=2884035 # 網易原創歌曲榜
# http://music.163.com/api/playlist/detail?id=19723756 # 雲音樂飆升榜
# http://music.163.com/api/playlist/detail?id=3778678 # 雲音樂熱歌榜
# http://music.163.com/api/playlist/detail?id=3779629 # 雲音樂新歌榜
# 歌單api
# http://music.163.com/api/playlist/detail?id=123415635 # 雲音樂歌單——【華語】中國風的韻律,中國人的印記
# http://music.163.com/api/playlist/detail?id=122732380 # 雲音樂歌單——那不是愛,只是寂寞說的謊

2. Fiddler的代理問題

利用Fiddler線上除錯的時候,直接在Chrome中重新整理,發現沒有抓取到core.js。
沒有core.js
查詢資料,發現雖然Fiddler安裝好就能用,但是抓的HTTPS過程不全,還需要在Chrome中配置一下。
配置方法:Fiddler Chrome配置和抓包
在SwitchyOmega外掛中切換為Fiddler代理後,還需要注意的是,不能直接重新整理介面,這樣Fiddler還是抓不到,要點選SwitchyOmega中設定的代理,通過這種方式重新整理介面,Fiddler就能抓到core.js了。
有core.js
同樣使用Fiddler的AutoResponder時,將瀏覽器JS替換為本地JS,也要用這種方式重新整理介面,consloe中才會有日誌輸出

3. 將網易雲JS中加密方法轉為Python實現遇到的問題

原文中對於第二個引數encSecKey固定為同一個值,雖然可以拿到返回的資料,但是不知道用固定值爬取的資料多了,會不會直接給我IP封掉,所以還是用Python實現了encSecKey值的獲取方法,程式碼如下:

def RSA_encrypt(n_str, e_str, random_str):  # RSA加密
    n = int(n_str, 16)  # RSA modulus,RSA演算法中大素數相乘的結果,16進位制
    e = int(e_str, 16)  # RSA演算法中的e,和n一起組成公鑰(n,e),16進位制
    cryptor = RSA.construct((n, e))  # 構造加密器
    # 網易雲JS中的encryptedString()將16位隨機字串倒序了,所以要生成與JS一樣的密文,這裡也要倒序,而且下面加密時,要求為位元組,所以編碼為ascii碼
    text = random_str[::-1].encode('ascii')
    encrypt_text = cryptor.encrypt(text, '')[0]  # 網易雲JS中第二個引數為空,這裡也為空。檢視encrypt()原始碼發現會返回兩個值,第一個是密文,第二個值總為空
    encrypt_text = binascii.b2a_hex(encrypt_text).decode('utf-8')  # encrypt_text為二進位制,轉為十六進位制然後再解碼成字串才是最後要post的密文
    return encrypt_text
    
def get_encSecKey(random_str, second_params, third_params):  # 產生POST的第二個引數
    encSecKey = RSA_encrypt(third_params, second_params, random_str)
    return encSecKey

這裡用的是RSA加密,需要注意的是網易雲JS中將輸入的16位隨機字串倒序了,所以這裡在加密之前也要將其倒序,並且轉為byte型別。
獲取第一個引數params時用的是AES加密,網易雲JS中採用了兩次加密,第二次加密直接對第一次加密結果進行加密,但在Python中第一次加密之後的結果為byte型別,第二次加密之前需要將其轉為String型別,否則會報TypeError: can’t concat str to bytes,程式碼如下:

def AES_encrypt(text, key):  # AES加密
    iv = '0102030405060708'
    pad = 16 - (len(text) % 16)  # 明文補足為16的倍數,如果正好是16的倍數,再補16位
    text += pad * chr(pad)  # chr()返回對應數值的ascii碼,如果少一位,補充一個數值1對應的ascii,如果少兩位,補充兩個數字2對應的ascii,以此類推
    encryptor = AES.new(key, AES.MODE_CBC, iv)  # key為金鑰,iv為初始偏移量
    encrypt_text = encryptor.encrypt(text)  # 加密
    encrypt_text = base64.b64encode(encrypt_text)  # 二級制編碼,用64個字元來表示任意二進位制資料
    return encrypt_text
    
def get_params(first_param, forth_param, random_str):  # 產生POST的第一個引數
    encText = AES_encrypt(first_param, forth_param).decode('utf-8')  # AES加密出來是byte型別,再次加密時需要先將其轉為String
    params = AES_encrypt(encText, random_str)
    return params

總結

本專案主要的時間花費在分析網易雲音樂的JS原始碼上,搞清楚了JS原始碼是怎麼請求資料的,後面爬蟲就很順利了,後面有時間還是要學一學JS,對於提高爬蟲效率有很大的幫助。

專案地址

網易雲音樂評論爬蟲
上面是專案地址,覺得還可以的話,給個star哦

參考資料

對網易雲音樂引數(params,encSecKey)的分析

解析網易雲音樂的加密方式

python3.x爬取網易雲音樂,超詳細版

python爬蟲例項–網易雲音樂排行榜爬蟲