天天看點

python爬蟲--下載下傳酷我音樂

本次練習的主要内容:

通過python爬蟲,破解酷我音樂的api,下載下傳音樂檔案到本地。

(一)項目概況

1. 這裡酷我音樂的首頁:

python爬蟲--下載下傳酷我音樂

2. 點選左上角的榜單,進去之後再點選具體歌名,跳轉到音樂播放頁面,可以線上聽音樂:

python爬蟲--下載下傳酷我音樂
python爬蟲--下載下傳酷我音樂

3. 本次項目的主要目标,就是通過音樂具體的播放頁面url,

即這樣的連結:http://www.kuwo.cn/yinyue/42484721?catalog=yueku2016

下載下傳該音樂到本地。

(二)網頁分析

1. 在音樂播放頁面打開開發者工具,檢視網絡請求:

在衆多網絡請求中,可以找到一個以.aac結尾的請求,猜測該請求就是目标音樂的請求。

python爬蟲--下載下傳酷我音樂

2. 分析可知,該請求具體情況如下:

請求類型:get

請求url:

http://ip.h5.nf03.sycdn.kuwo.cn/ee3a8426c1def769b22e5c23639d6220/5b2b12a1/resource/a1/65/1/2669068103.aac

是以,隻要模拟該get請求,就能拿到aac檔案。

但是該url裡面有許多陌生的字段,具體是從哪裡來的呢?

3. 經查找,可以在下面的請求中的response的headers裡面,找到上面的url:

python爬蟲--下載下傳酷我音樂

4. 經分析該請求的情況如下:

請求類型:get

請求url:

http://antiserver.kuwo.cn/anti.s?format=aac|mp3&rid=MUSIC_42484721&type=convert_url&response=res

注意該請求傳回的狀态碼是302。

仔細觀察該請求的參數,發現隻有“MUSIC_42484721”這個字段是動态變更的,其他都是固定的。

那麼該MUSIC字段是從哪裡來的呢?

仔細想想,原來就是音樂播放頁面的url中包含的一個字段:http://www.kuwo.cn/yinyue/42484721?catalog=yueku2016

5. 這樣就很明确了,下面梳理下思路:

- 通過音樂播放頁面url,拿到類似這樣的字段 “42484721”

- 通過該字段,構造第4步的get請求,拿到response的headers的location字段

- 通過location字段,發送get請求,拿到aac檔案

(三)核心代碼實作

1. 擷取音樂播放url中特定字段

import requests
import re

s = requests.session()
filename = input("請輸入音樂檔案儲存的本地路徑:").strip()
base_url = input("請輸入音樂播放頁面url:").strip()
base_number = re.findall(r"(?:http://www.kuwo.cn/yinyue/)(\d+)(?:\?catalog=yueku2016)", base_url)[0]           

2. 通過上面的字段,構造第一個get請求,擷取傳回頭中的location字段

def get_url():
    headers = {
        'Accept': '*/*',
        'Accept-Encoding': 'identity;q=1, *;q=0',
        'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
        'Connection': 'keep-alive',
        'Host':'antiserver.kuwo.cn',
        'Range': 'bytes=0-',
        'User-Agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36',
        'Accept':'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',
        'Referer':base_url
    }
    url = "http://antiserver.kuwo.cn/anti.s?format=aac|mp3&rid=MUSIC_"+ base_number +"&type=convert_url&response=res"
    r = s.get(url, headers=headers, allow_redirects=False)
    return r.headers['Location']           

3. 通過location字段中的url,擷取到aac檔案資料

注意在網絡分析時的截圖,可以看到該請求的傳回的狀态碼是206,這是由于該請求的請求頭中添加了Range字段,代表僅請求部分内容,我這裡設定為了'Range': 'bytes=0-',意思是請求從0位元組之後的所有内容。

def get_aac(url):
	base_host = re.findall(r"(?:http://)(.*)", url)[0]
	base_host = base_host.split('/')[0]
	headers ={
            'Accept': '*/*',
            'Accept-Encoding': 'identity;q=1, *;q=0',
            'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
            'Connection': 'keep-alive',
            'Host': base_host,
            'User-Agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36',
            'Referer':base_url,
            'Range': 'bytes=0-'
           }
	r = s.get(url, headers=headers, stream=True)
	return r           

4. 将aac檔案資料寫入到本地

def save_aac(filename, res):
	with open(filename, 'wb') as fd:
	    for chunk in res.iter_content(chunk_size=128):
	        fd.write(chunk)           

5. 代碼中的注意事項

實際寫代碼的過程中,發現酷我對請求頭的檢查非常嚴格,是以請求頭務必根據實際情況編寫準确,否則無法正确擷取資料。

(四)項目結果

通過給定的音樂播放url,就可以将該音樂下載下傳到指定的本地檔案存儲路徑中。

(五)下一步

1. 代碼中增加相應的錯誤檢查

2. 可将本次代碼作為批量爬取酷我音樂項目的一部分。

本文僅供學習交流使用,請勿将其用于違法目的。