小白都懂的Python爬蟲之網易雲音樂下載

目標

偶然的一次機會聽到了房東的貓的《雲煙成雨》,瞬間迷上了這慵懶的嗓音和學生氣的歌詞,而後一直去循環聽她們的歌。而後還特地去刷了動漫《我是江小白》,好期待第二季...python

我多想在見你,哪怕匆匆一眼就別離...

好了,不說廢話了。此次的目標主要是根據網易雲中歌手的ID,下載該歌手的熱門音樂的歌詞和音頻,並保存到本地的文件夾中。git

配置基礎

  • Python
  • Selenium(配置方法參照:Selenium配置)
  • Chrome瀏覽器(其它的也能夠,須要進行相應的修改)

分析

若是爬取過網易雲的網站的小夥伴都應該知道網易雲是有反爬取機制的,POST時須要對一些信息的參數進行加密函數的模擬。可是這裏爲了簡便,小白也能理解。直接使用了Selenium來模擬登陸,而後使用接口來直接下載音樂和歌詞。github

實驗步驟web

  1. 根據歌手ID獲取該歌手的熱門歌曲列表,歌曲名稱和連接,並保存到csv文件中;
  2. 讀取csv文件,根據歌曲連接,提取歌曲ID,而後利用相應的接口,下載音樂和歌詞;
  3. 將音樂和歌詞保存到本地。

Python實現

該部分將對幾個關鍵的函數進行介紹...正則表達式

獲取歌手信息

利用Selenium咱們就不須要看對網頁的請求了,直接能夠從網頁源碼中提取相應的信息。查看歌手頁面源碼能夠發現,咱們須要的信息在iframe框架內,因此咱們先須要切換到iframe:json

browser.switch_to.frame('contentFrame')

繼續往下看,發現咱們須要的歌曲名字和連接是在id="hotsong-list"的標籤中,而後每一行對應的是一個tr標籤。因此先獲取全部的tr內容,而後遍歷單個trapi

data = browser.find_element_by_id("hotsong-list").find_elements_by_tag_name("tr")

注意:前一個是find_element,後一個是find_elements,後者返回一個列表。瀏覽器

接下來就是解析單個tr標籤的內容,獲取歌曲名字和連接,能夠發現二者在class="txt"標籤中,並且連接是href屬性,名字是title屬性,能夠直接經過get_attribute()函數獲取。app

for i in range(len(data)):
    content = data[i].find_element_by_class_name("txt")
    href = content.find_element_by_tag_name("a").get_attribute("href")
    title = content.find_element_by_tag_name("b").get_attribute("title")
    song_info.append((title, href))

下載歌詞

網易雲有個獲取歌詞的接口,連接爲:http://music.163.com/api/song...框架

連接中的數字就是歌曲的id,因此咱們擁有歌曲id後,能夠直接從該連接下載歌詞,歌詞文件是json格式,因此咱們須要用到json包。

並且直接獲取的歌詞中,每行有一個時間軸,須要用正則表達式來剔除,完整代碼以下:

def get_lyric(self):
    url = 'http://music.163.com/api/song/lyric?' + 'id=' + str(self.song_id) + '&lv=1&kv=1&tv=-1'
    r = requests.get(url)
    json_obj = r.text
    j = json.loads(json_obj)
    lyric = j['lrc']['lyric']
    # 利用正則表達式去除時間軸
    regex = re.compile(r'\[.*\]')
    final_lyric = re.sub(regex, '', lyric)
    return final_lyric

下載音頻

網易雲也提供了音頻文件的接口,連接爲:http://music.163.com/song/med...

連接中的數字爲歌曲的id,能夠直接根據歌曲的id來下載音頻文件。完整代碼以下:

def get_mp3(self):
    url = 'http://music.163.com/song/media/outer/url?id=' + str(self.song_id)+'.mp3'
    try:
        print("正在下載:{0}".format(self.song_name))
        urllib.request.urlretrieve(url, '{0}/{1}.mp3'.format(self.path, self.song_name))
        print("Finish...")
    except:
        print("Fail...")

Reference

源碼地址

相關文章
相關標籤/搜索