文章目录
- 网页分析
- 明确思路
- 手动操作
- 代码实现
- 1. 导入需要的包
- 2. 建立主函数
- 3. 获取用户输入的歌曲网址
- 4. 获取歌名、歌手
- 5. 获取音频url
- 6. 下载音频
- 7. 主函数润色
- 8. 最终代码
网页分析
明确思路
首先我们明确写爬虫的思路,我们想要用程序实现下载酷我音乐的功能,就必须先手动操作一遍,看看我们自己能不能在网站的后台数据包中找到音频文件的链接,然后回溯整个寻找的过程,想办法用代码来实现它
同时,如果我们想爬取很多歌曲,思路也应该是以一首歌曲为例,如果能够根据这首歌曲的url爬取到音频,那么爬取很多歌曲也只是找每个歌曲的url而已。
手动操作
明确了思路,我们废话不多说,就以最近比较火的“热爱105度的你”这首歌为例
首先要通过后台数据包找到其音频的url
右键检查,刷新页面开始抓包,通常这些音频url都藏在json格式的数据包中,因此我们需要重点关注json格式的数据包
在network菜单下找到XHR分类,该分类下大部分都是json格式的数据,我们要找的音频url很可能就藏在这里面
一个一个的寻找,重点关注url,特别要关注url的后缀是不是.mp3等音频文件的后缀
我们在其中一个json数据包中找到包含mp3后缀的url,打开看一下是不是该歌曲的音频文件
在网址栏输入url,打开后发现它确实是该歌曲的音频
我们可以通过代码发出get请求将该页面字节流写入音频文件,从而实现音乐的下载。
OK,那么现在问题的关键就在于——如何根据歌曲的网址所包含的信息来找到这个数据包的url,从而发送请求得到json数据,并在其中找到音频的url
我们先回到这个json数据包的headers,可以看到这个数据包的url
很明显这个url包含很多parameters,这很有可能是一个线索
我们直接划到最底下看所有的parameters
这些parameters中,一些是共性化的,另一些是个性化的(即与该歌曲的id有关的)
一般来说,这些网站都会给每个歌曲一个id用于区分,这个id通常都包含在歌曲的网址中
观察歌曲的网址可以发现,每一首歌曲都有一个特定的id号,比如这首歌是71988945
我们再回到这些parameters中观察,可以看出rid就是这首歌曲的id
因此我们就可以通过歌曲的网址找到其id号,再传入id号参数发出请求得到json数据包,从json数据包中可以得到音频的url,最后访问音频url爬取音频文件
分析完毕,我们直接上代码!!
代码实现
1. 导入需要的包
import requests
from bs4 import BeautifulSoup
import json
2. 建立主函数
def main():
song_url, rid = inputUrl()
file_name = getFileName(song_url)
mp3_url = getMp3Url(rid)
downloadMusic(file_name, mp3_url)
3. 获取用户输入的歌曲网址
def inputUrl():
song_url = input('请输入歌曲地址:') # 比如http://www.kuwo.cn/play_detail/71988945
start = song_url.find('play_detail/') + len('play_detail/')
rid = song_url[start:]
return song_url, rid
4. 获取歌名、歌手
def getFileName(song_url):
headers = {
'Cookie':'_ga=GA1.2.2108030690.1627639450; _gid=GA1.2.1568217760.1627639450; Hm_lvt_cdb524f42f0ce19b169a8071123a4797=1627639450; Hm_lpvt_cdb524f42f0ce19b169a8071123a4797=1627640133; kw_token=800OY0MAXO5',
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.107 Safari/537.36'
}
html = requests.get(url=song_url, headers=headers)
soup = BeautifulSoup(html.text, 'html.parser')
song_name = soup.select('.song_name.flex_c .name')[0].text.strip()
singer_name = soup.select('.artist_name.flex_c .name')[0].text.strip()
file_name = f'{song_name} - {singer_name}.mp3'
return file_name
5. 获取音频url
def getMp3Url(rid):
url = 'http://www.kuwo.cn/url'
params = {
'format':'mp3',
'rid':f'{rid}',
'response':'url',
'type':'convert_url3',
'br':'128kmp3',
'from':'web',
't':'1627639481401',
'httpsStatus':'1',
'reqId':'8e9e59a1-f11d-11eb-be6e-cf60d243bdd8'
}
headers = {
'Cookie':'_ga=GA1.2.2108030690.1627639450; _gid=GA1.2.1568217760.1627639450; _gat=1; Hm_lvt_cdb524f42f0ce19b169a8071123a4797=1627639450; Hm_lpvt_cdb524f42f0ce19b169a8071123a4797=1627639460; kw_token=XXWW3V5QGC',
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.107 Safari/537.36'
}
html = requests.get(url=url, params=params, headers=headers)
dic = json.loads(html.text)
mp3_url = dic['url']
return mp3_url
6. 下载音频
def downloadMusic(file_name, mp3_url):
mp3_data = requests.get(url=mp3_url).content
with open(file_name, 'wb') as f:
f.write(mp3_data)
7. 主函数润色
def main():
try:
song_url, rid = inputUrl()
except:
print('rid获取失败(可能原因:歌曲地址错误)')
return
try:
file_name = getFileName(song_url)
except:
print('页面解析失败')
return
try:
mp3_url = getMp3Url(rid)
except:
print('json数据获取失败')
return
try:
downloadMusic(file_name, mp3_url)
except:
print('音乐下载失败')
return
8. 最终代码
import requests
from bs4 import BeautifulSoup
import json
def inputUrl():
song_url = input('请输入歌曲地址:') # 比如http://www.kuwo.cn/play_detail/71988945
start = song_url.find('play_detail/') + len('play_detail/')
rid = song_url[start:]
return song_url, rid
def getMp3Url(rid):
url = 'http://www.kuwo.cn/url'
params = {
'format':'mp3',
'rid':f'{rid}',
'response':'url',
'type':'convert_url3',
'br':'128kmp3',
'from':'web',
't':'1627639481401',
'httpsStatus':'1',
'reqId':'8e9e59a1-f11d-11eb-be6e-cf60d243bdd8'
}
headers = {
'Cookie':'_ga=GA1.2.2108030690.1627639450; _gid=GA1.2.1568217760.1627639450; _gat=1; Hm_lvt_cdb524f42f0ce19b169a8071123a4797=1627639450; Hm_lpvt_cdb524f42f0ce19b169a8071123a4797=1627639460; kw_token=XXWW3V5QGC',
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.107 Safari/537.36'
}
html = requests.get(url=url, params=params, headers=headers)
dic = json.loads(html.text)
mp3_url = dic['url']
return mp3_url
def getFileName(song_url):
headers = {
'Cookie':'_ga=GA1.2.2108030690.1627639450; _gid=GA1.2.1568217760.1627639450; Hm_lvt_cdb524f42f0ce19b169a8071123a4797=1627639450; Hm_lpvt_cdb524f42f0ce19b169a8071123a4797=1627640133; kw_token=800OY0MAXO5',
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.107 Safari/537.36'
}
html = requests.get(url=song_url, headers=headers)
soup = BeautifulSoup(html.text, 'html.parser')
song_name = soup.select('.song_name.flex_c .name')[0].text.strip()
singer_name = soup.select('.artist_name.flex_c .name')[0].text.strip()
file_name = f'{song_name} - {singer_name}.mp3'
return file_name
def downloadMusic(file_name, mp3_url):
mp3_data = requests.get(url=mp3_url).content
with open(file_name, 'wb') as f:
f.write(mp3_data)
def main():
try:
song_url, rid = inputUrl()
except:
print('rid获取失败(可能原因:歌曲地址错误)')
return
try:
file_name = getFileName(song_url)
except:
print('页面解析失败')
return
try:
mp3_url = getMp3Url(rid)
except:
print('json数据获取失败')
return
try:
downloadMusic(file_name, mp3_url)
except:
print('音乐下载失败')
return
if __name__ == '__main__':
main()