python-網易雲音樂搜尋下載下傳腳本
- 前言
- 開發環境及所需的庫
-
- 開發環境
- 所需的庫
- 思想
-
- 搜尋
- 下載下傳
- 儲存
- 實作
-
- 搜尋
- 下載下傳和儲存
- 主函數和輔助函數
- 效果
- 結語
前言
之前寫過如何從網易雲網頁下載下傳歌曲,但是感覺太麻煩了,于是就想着寫一個腳本來完成搜尋加下載下傳的功能。
開發環境及所需的庫
開發環境
Windows 10
python 3.7
所需的庫
requests
re
time
selenium
prettytable
思想
搜尋
使用爬蟲,通路https://music.163.com/#/search/m/?s=音樂名&type=1,來的到歌曲清單、歌手以及歌曲ID(下載下傳音樂時需要)
下載下傳
網易雲網頁播放音樂時會調用連結http://music.163.com/song/media/outer/url?id=音樂ID.mp3,來擷取音樂,是以我們才需要音樂ID
儲存
直接将爬取到的mp3儲存到檔案就行了
實作
調用庫
from selenium.webdriver.firefox.options import Options
import requests
import re
from selenium import webdriver
from time import sleep
from prettytable import PrettyTable
搜尋
本來我想用requests庫來實作歌曲清單的爬取,但是,由于頁面中嵌套着一個iframe,導緻無法得到(也可能是我太菜了)。是以使用selenium來實作。
我使用的是火狐,先配置selenium,不顯示gui
# 設定options
firefox_options = Options()
firefox_options.add_argument("--headless")
firefox_options.add_argument("--disable-gpu")
搜尋音樂的函數:
# 搜尋音樂
def SearchMusic(name):
url_search = "https://music.163.com/#/search/m/?s="+name+"&type=1"
# 初始化
browser = webdriver.Firefox(executable_path="geckodriver.exe", options=firefox_options)
# 歌曲搜尋
browser.get(url=url_search)
# 切換iframe
browser.switch_to.frame("g_iframe")
sleep(0.5)
# 頁面資訊
page_text = browser.execute_script("return document.documentElement.outerHTML")
# 退出
browser.quit()
# 正規表達式
re1 = '<a.*?id="([0-9]*?)"'
re2 = '<b title="(.*?)">.*?<span class="s-fc7">'
re3 = 'class="td w1"><div class="text"><a href=".*?" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" >(.*?)</div></div>'
id_list = re.findall(re1, page_text, re.M)[::2]
song_list = re.findall(re2, page_text, re.M)
singer_list = re.findall(re3, page_text, re.M)
total_list = list(zip(song_list, singer_list, id_list))
# 指令行表格
table = PrettyTable(["序号", "音樂名", "歌手", "音樂ID"])
for i in range(len(total_list)):
# 處理多個歌手
# 處理不完全,可能有BUG
if "<a href=" in total_list[i][1]:
re4 = '(.*?)</a>'
temp = re.findall(re4, total_list[i][1], re.M)
re5 = '<a href=".*?" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" >(.*?)</a>'
singer = ""
for s in temp:
t = re.findall(re5, s+"</a>", re.M)
if t == []:
singer += s + "/"
else:
singer += t[0] + "/"
total_list[i] = (total_list[i][0], singer[:-1], total_list[i][2])
else:
if total_list[i][1][-1] != ">":
temp = total_list[i][1].replace("</a>","")
else:
temp = total_list[i][1][:-4]
total_list[i] = (total_list[i][0], temp, total_list[i][2])
# 将資料加入到表格
table.add_row([str(i+1), total_list[i][0], total_list[i][1], total_list[i][2]])
# 輸出表格
print(table,"\n")
return total_list
火狐的webdrive是geckodriver.exe,可以從網上下載下傳,并放到腳本目錄。
中間的正規表達式是為了比對歌曲名、歌手、歌曲ID,同時對于多個歌手的情況,不能隻用一個正規表達式解決,我試了好多次,才可能成功,不一定能保證一定能成功,是以可能存在BUG。
對于清單的輸出,我才用的是prettytable來使得指令行輸出更好看。
下載下傳和儲存
下載下傳時記得設定header,否則會遇見網絡通路頻繁的傳回。
下載下傳和儲存函數:
# 下載下傳音樂
def GetMusic(music_id):
head = {"User-Agent":'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_8; en-us) AppleWebKit/534.50 (KHTML, like Gecko) Version/5.1 Safari/534.50',
"Referer": "https://music.163.com/"}
url_music = "http://music.163.com/song/media/outer/url?id="+music_id+".mp3"
html = requests.get(url_music, headers=head)
with open(music_id+".mp3", "wb") as f:
f.write(html.content)
儲存到本地時,我是用的是用音樂ID名儲存的,是以當下載下傳多個音樂時,要厘清楚音樂名。
主函數和輔助函數
# 輸出菜單
def menu():
print("網易雲音樂搜尋下載下傳")
print("1.音樂搜尋")
print("2.音樂下載下傳(需要音樂ID)")
print("3.退出")
print("注: 音樂搜尋可以獲得音樂ID\n")
# 主函數
def main():
while 1:
menu()
num = input("請輸入序号(1-3):")
try:
num = int(num)
except:
print("錯誤序号!\n")
continue
if num not in [1,2,3]:
print("錯誤序号!\n")
if num == 1:
name = input("\n輸入歌名(輸入q傳回):")
if name == "q":
continue
total_list = SearchMusic(name)
elif num == 2:
music_id = input("\n請輸入歌曲id(輸入q傳回):")
if music_id == "q":
continue
print("下載下傳中")
GetMusic(music_id)
print("下載下傳完成\n")
elif num == 3:
break
menu函數用于輸出菜單。
主函數用while循環。
效果
檔案:
菜單和搜尋:
下載下傳:
結語
希望大家可以喜歡,代碼檔案和geckodriver.exe我會放到GitHub上,希望大家可以點一個star。