python爬蟲(chóng)--不限平臺(tái)歌曲下載(收費(fèi)也可)

1.起因

自己一直都想聽(tīng)胖倫的歌,但是網(wǎng)易云又下架了,其他音樂(lè)平臺(tái)又需要會(huì)員
于是自己就嘗試著看看能不能?chē)L試通過(guò)爬蟲(chóng)把胖倫的歌下載下來(lái)。但是奈何博主自身的水平有限。如果直接通過(guò)QQ音樂(lè)等音樂(lè)網(wǎng)站爬的話(huà),難度極大,畢竟騰訊他們也不是傻子,肯定是做好了一系列的反扒機(jī)制的。既然這樣,那我們就要選擇放棄了嗎?經(jīng)過(guò)百度,博主終于搜到了一個(gè)網(wǎng)站。
網(wǎng)站鏈接:http://music.onlychen.cn/

在這里插入圖片描述

這個(gè)網(wǎng)站已經(jīng)幫我們做好了解密的工作,我們只需要分析該網(wǎng)站的網(wǎng)頁(yè)結(jié)構(gòu)就行了。
雖然我們不能直接剛QQ音樂(lè),但是我們剛這種網(wǎng)站還是沒(méi)什么問(wèn)題的

2.分析網(wǎng)頁(yè)結(jié)構(gòu)

首先按照慣例先分析網(wǎng)頁(yè)結(jié)構(gòu)
在這里插入圖片描述

其實(shí)這里我們的工作就已經(jīng)完成了,如果只想下載這一首七里香的話(huà)。但是博主我會(huì)是那樣的人嗎???肯定不是,博主的原則就是我全都要。


image.png

所以我們就要重新理清思路。我們整個(gè)的流程是啥???
之前我們爬蟲(chóng)的思路就是


image.png

現(xiàn)在我們的思路其實(shí)還是這個(gè),但是大家發(fā)現(xiàn)了沒(méi)有這次有我們能夠直接請(qǐng)求的url地址嗎?或者說(shuō)這次我們直接請(qǐng)求這個(gè)url地址我們能夠直接得到我們想要的信息嗎?顯然是不行的,我們必須進(jìn)行form表單的提交就是下面這個(gè)操作:


在這里插入圖片描述

這樣提交完這些參數(shù)后,我們才真正能夠獲取到我們想要的網(wǎng)頁(yè)。不清楚的話(huà),我們 可以看下面這張圖,大家就懂了。


在這里插入圖片描述

請(qǐng)求到網(wǎng)頁(yè)之后我們看我們獲得信息到底是什么樣的


在這里插入圖片描述

3.代碼實(shí)現(xiàn)

3.1請(qǐng)求網(wǎng)頁(yè)

既然這樣大致的過(guò)程我們已經(jīng)懂了,接下來(lái)我們就來(lái)實(shí)現(xiàn)。
首先我們先將整個(gè)網(wǎng)頁(yè)的請(qǐng)求信息拿下來(lái)。

headers={
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36',}
    url='http://music.onlychen.cn/'
    response=requests.get(url,headers=headers)
    print(response.content.decode('utf-8'))

但是我們發(fā)現(xiàn)這樣請(qǐng)求之后卻返回了這樣的一個(gè)信息;


在這里插入圖片描述

現(xiàn)在我們來(lái)思考,之前是要傳入表單的數(shù)據(jù)的,既然需要傳入數(shù)據(jù)那么一般就是用post請(qǐng)求,之前我們一直都是通過(guò)get請(qǐng)求來(lái)請(qǐng)求網(wǎng)頁(yè)的。于是我們簡(jiǎn)單修改一下代碼:

params={
        'input':'七里香',
        'filter':'name',
        'type':'qq',
        'page':1,
    }
    headers={
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36',}
    url='http://music.onlychen.cn/'
    response=requests.post(url,headers=headers,data=params)
    print(response.content.decode('utf-8'))

但是我們這樣改完之后仍然不能訪(fǎng)問(wèn),之后我們重新去看一下網(wǎng)頁(yè)的請(qǐng)求頭,這時(shí)候我們發(fā)現(xiàn)一個(gè)東西:
在這里插入圖片描述

這表示我們的請(qǐng)求是 異步的,所以我們必須把他也放到請(qǐng)求頭之中,這樣我們?cè)賮?lái)嘗試一下,雖然信息我們是請(qǐng)求下來(lái)了,但是顯然我們可以發(fā)現(xiàn) 中文根本無(wú)法顯示,但是的確是我們之前看到的網(wǎng)頁(yè)信息。

image.png

這時(shí)我們想想之前我們看到的網(wǎng)頁(yè)信息,可以清楚的看到就是一個(gè)json數(shù)組,并不是HTML語(yǔ)言的格式,所以我們不能再用這種方式來(lái)解讀網(wǎng)頁(yè)信息,用下面這個(gè):

print(response.json())

這樣我們便能看到我們想要的數(shù)據(jù)了;


image.png

3.2篩選數(shù)據(jù)

既然數(shù)據(jù)我們已經(jīng)請(qǐng)求到了,那么我們現(xiàn)在就應(yīng)該做篩選我們需要的數(shù)據(jù),因?yàn)檫@里的數(shù)據(jù)都是json格式的,所以不能通過(guò)之前我們使用的xpath來(lái)進(jìn)行篩選了,但是json同樣提供了相應(yīng)的模塊來(lái)幫助我們篩選數(shù)據(jù)那就是jsonpath,具體用法其實(shí)都一樣,這里我就只寫(xiě)這兩個(gè)范例了,剩下的大家可以自行百度:

    data=response.json()
    url=jsonpath.jsonpath(data,'$..url')[0]
    title=jsonpath.jsonpath(data,'$..title')[0]

3.3下載資源

這樣我們就已經(jīng)獲得了我們所需要的資源的鏈接了,這樣我們就能將它下載下來(lái)了
這里還是直接使用我們之前用的urllib.request.urlretrieve(url,path) 就可以實(shí)現(xiàn)了

def download(url,title):
    dir_name=r'D:\software\python\python爬蟲(chóng)\vip音樂(lè)'
    os.makedirs(dir_name,exist_ok=True)
    path=dir_name+'/{}.mp3'.format(title)
    print("正在下載:{}".format(title))
    urllib.request.urlretrieve(url,path)
    print("{},已經(jīng)下載完畢".format(title))

3.4編寫(xiě)簡(jiǎn)單頁(yè)面

到這里我們的爬蟲(chóng)就已經(jīng)編寫(xiě)好了。但是博主我自己想了想能不能通過(guò)制作成一個(gè)應(yīng)用,這樣,那我就可以想下啥就下啥了,來(lái)說(shuō)干就干。那么既然這樣我們就需要首先需要一個(gè)頁(yè)面,這里我選擇的python中最簡(jiǎn)單的模塊進(jìn)行編寫(xiě)了,大家可以去選擇更好的工具進(jìn)行編寫(xiě)。

# 界面制作
from tkinter import *
# 創(chuàng)建一個(gè)窗口
root=Tk()
#初始化單選框的值就是將這些單選框組合起來(lái)
v = IntVar()
v.set(1)
# 添加標(biāo)題
root.title('全網(wǎng)音樂(lè)下載器')
# 修改窗口大小
root.geometry('560x430+400+200')

# 標(biāo)簽組件
label=Label(root,text='輸入下載的歌曲名:',font=('黑體常規(guī)',20))
#標(biāo)簽的布局
label.grid(row=0,columns=2)

# 輸入框組件
entry=Entry(root,font=('黑體常規(guī)',20),width=15)
#標(biāo)簽的布局
entry.grid(row=0,column=2,columns=2)

#單選框組件
Radiobutton(root, text="網(wǎng)易云",variable=v,value=1,width=10).grid(row=1, column=0)
Radiobutton(root, text="qq音樂(lè)",variable=v,value=2,width=10).grid(row=1, column=1)
Radiobutton(root, text="酷我",variable=v,value=3,width=10).grid(row=1, column=2)
Radiobutton(root, text="酷狗",variable=v,value=4,width=10).grid(row=1, column=3)

#文本框組件
text=Listbox(root,font=('黑體常規(guī)',16),width=50,heigh=15)
text.grid(row=2,columns=4)

#按鈕組件
button1=Button(root,text='開(kāi)始下載',font=('黑體常規(guī)',15),command=get_music_name)#并且定義按鈕的點(diǎn)擊事件
button1.grid(row=3,column=0)

#按鈕組件
button2=Button(root,text='退出程序',font=('黑體常規(guī)',15),command=root.quit)#并且定義按鈕的點(diǎn)擊事件
button2.grid(row=3,column=3)

root.mainloop()

這樣我們的頁(yè)面就編寫(xiě)好了。如下:


在這里插入圖片描述

雖然很丑,但起碼還是畫(huà)出來(lái)了的

3.5數(shù)據(jù)綁定

頁(yè)面編寫(xiě)了,我們就需要將數(shù)據(jù)綁定到一起,否則也是沒(méi)什么用的:

def get_music_name():
    #獲取輸入框的值
    name=entry.get()
    #獲取單選框的值,因?yàn)閱芜x框的值只能是int類(lèi)型,所以這里我們不能直接獲得,只能通過(guò)條件判斷語(yǔ)句進(jìn)行type的賦值
    if v.get()==1:
        type='netease'
    elif v.get()==2:
        type='qq'
    elif v.get() == 3:
        type = 'kuwo'
    elif v.get() == 4:
        type = 'kugou'
    params={
        'input':name,
        'filter':'name',
        'type':type,
        'page':1,
    }
    headers={
        'X-Requested-With': 'XMLHttpRequest',
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36',}
    url='http://music.onlychen.cn/'
    response=requests.post(url,data=params,headers=headers)
    data=response.json()
    url=jsonpath.jsonpath(data,'$..url')[0]
    title=jsonpath.jsonpath(data,'$..title')[0]
    download(url,title)

# 下載歌曲
def download(url,title):
    dir_name=r'D:\software\python\python爬蟲(chóng)\vip音樂(lè)'
    os.makedirs(dir_name,exist_ok=True)

    path=dir_name+'/{}.mp3'.format(title)
    #在文本框中提示下載信息
    text.insert(END,'{}正在下載'.format(title))
    text.see(END)
    text.update()

    urllib.request.urlretrieve(url,path)

    text.insert(END, '{}已經(jīng)下載完畢'.format(title))
    text.see(END)
    text.update()

到這里我們所有的程序就已經(jīng)全部編寫(xiě)完畢了。

4.源代碼

這是完整的源代碼

import requests
import jsonpath
import urllib.request
import os
# 獲取歌曲的詳細(xì)信息包括鏈接以及標(biāo)題
def get_music_name():
    name=entry.get()
    if v.get()==1:
        type='netease'
    elif v.get()==2:
        type='qq'
    elif v.get() == 3:
        type = 'kuwo'
    elif v.get() == 4:
        type = 'kugou'
    params={
        'input':name,
        'filter':'name',
        'type':type,
        'page':1,
    }
    headers={
        'X-Requested-With': 'XMLHttpRequest',
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36',}
    url='http://music.onlychen.cn/'
    response=requests.post(url,data=params,headers=headers)
    data=response.json()
    url=jsonpath.jsonpath(data,'$..url')[0]
    title=jsonpath.jsonpath(data,'$..title')[0]
    download(url,title)

# 下載歌曲
def download(url,title):
    dir_name=r'D:\software\python\python爬蟲(chóng)\vip音樂(lè)'
    os.makedirs(dir_name,exist_ok=True)

    path=dir_name+'/{}.mp3'.format(title)
    text.insert(END,'{}正在下載'.format(title))
    text.see(END)
    text.update()

    urllib.request.urlretrieve(url,path)

    text.insert(END, '{}已經(jīng)下載完畢'.format(title))
    text.see(END)
    text.update()

# 界面制作
from tkinter import *
# 創(chuàng)建一個(gè)窗口
root=Tk()
v = IntVar()
v.set(1)
# 添加標(biāo)題
root.title('全網(wǎng)音樂(lè)下載器')
# 修改窗口大小
root.geometry('560x430+400+200')
# 標(biāo)簽組件
label=Label(root,text='輸入下載的歌曲名:',font=('黑體常規(guī)',20))
label.grid(row=0,columns=2)

entry=Entry(root,font=('黑體常規(guī)',20),width=15)
entry.grid(row=0,column=2,columns=2)

Radiobutton(root, text="網(wǎng)易云",variable=v,value=1,width=10).grid(row=1, column=0)
Radiobutton(root, text="qq音樂(lè)",variable=v,value=2,width=10).grid(row=1, column=1)
Radiobutton(root, text="酷我",variable=v,value=3,width=10).grid(row=1, column=2)
Radiobutton(root, text="酷狗",variable=v,value=4,width=10).grid(row=1, column=3)

text=Listbox(root,font=('黑體常規(guī)',16),width=50,heigh=15)
text.grid(row=2,columns=4)

button1=Button(root,text='開(kāi)始下載',font=('黑體常規(guī)',15),command=get_music_name)
button1.grid(row=3,column=0)

button2=Button(root,text='退出程序',font=('黑體常規(guī)',15),command=root.quit)
button2.grid(row=3,column=3)

root.mainloop()

5.效果演示

image.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀(guān)點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容