前言:
开始打算弄个逆向工程,然后把网易云的歌爬下来,但是这件事情是违法的,绝对不是学艺不精,所以我又搜了一个网易云的开放API,虽然下载不了付费歌曲,但是让我这个小白练一练爬虫还是绰绰有余的。
思路:
我最开始以为这个东西很简单,所以我试着通过网易云的搜索栏和post指令获取某一首歌曲的id,但是实际过程中发现post的负载是经过js加密而且高度混淆的,虽然我一直在研究逆向这个东西,但是以我现在目前水平搞出来花费的时间太长,所以我找到网易云的开放api接口来获取免费的音乐。
代码编写:
总体结构:
通过用户输入网易云某个作者的网易云某个作者的热门作品界面链接来获取该作者所有作品。网易云音乐并不是单首音乐作为一个列表的形式展示在一个页面里的,而是放在一个个对应的专辑里面,所以我们先需要找到作者id,再通过作者id找到该作者所有专辑的id,再通过专辑找到单首音乐id,再通过单首音乐id下载该歌曲,其中还涉及到url的拼接;文件的写入;链表,正则表达式,requests,BeautifulSoup4,正则表达式等的使用。总体下来还是很繁琐的。
函数:
定义变量并导入库:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| import re from time import sleep import requests from bs4 import BeautifulSoup
nnnum = 1 nnum = 0 key = [0] tag = '=' n = 0 music_id = [0] * 100 headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) " "Chrome/58.0.3029.110 Safari/537.3", "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8" }
|
首先:
我们需要把用户输入的链接进行处理得到作者id。
1 2 3 4 5 6
| ''' 这里的tag是字符串类型的等于号,我们将用户输入的url传入函数,并通过split方法将字符串分为两半分别写入index列表的第一跟第二个元素,然后返回第二个元素。 ''' def id(url, tag): index = url.split(tag) return index[1] if len(index) > 1 else exit('输入错误')
|
然后:
我们再写一个方法把每首歌一一对应的专辑id提取出来。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| def get_id(url, headers, n): album_repo = requests.get(url, headers=headers) album_repo.encoding = 'utf-8' album_soup = BeautifulSoup(album_repo.text, 'html.parser') album_ids = album_soup.find_all('a', {'class': 'tit s-fc0'}) for album_id in album_ids: music_id[n] = id(album_id.get('href'), tag) n += 1 return album_ids
|
接着:
我们再写一个函数用专辑id找到对应歌曲的id和歌曲的名称。(这里用re库跟正则表达式会比较方便一点)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| def get_name_id(num): url = 'https://music.163.com/album?id=' + str(music_id[num]) song_repo = requests.get(url=url, headers=headers) song_repo.encoding = 'utf-8' song_soup = BeautifulSoup(song_repo.text, 'html.parser') song = song_soup.find('ul', {'class': 'f-hide'}) pattern = r'\d+' song_id = re.findall(pattern, str(song)) pattern = r'[\u4e00-\u9fa5]+' song_name = re.findall(pattern, str(song))
if song_name != []: return song_name[0], song_id[0] else: exit('程序结束,共下载' + str(nnum) + '首歌曲')
|
最后:
我们用获取的id来下载歌曲
1 2 3 4 5 6 7 8 9 10
| def downloda(name, music_id, nnnum): downloda_api = 'http://music.163.com/song/media/outer/url?id=' + music_id music = requests.get(url=downloda_api, headers=headers) try: with open(str(nnnum) + '.' + name + '.mp3', 'wb') as file: file.write(music.content) print(str(nnnum) + '.' + name + '下载成功') except: print('下载异常,歌曲可能需要vip权限才能下载')
|
main:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| url_album = input('请输入网易云音乐歌手页面链接')
while True: url = 'https://music.163.com/artist/album?id=' + id(url_album, tag) + '&limit=12&offset=' + str(n) key = get_id(url, headers, n) if not key: break print(music_id) n += 12 sleep(1)
while nnum < len(music_id): song_name, song_id = get_name_id(nnum) downloda(song_name, song_id, nnnum) nnum += 1 nnnum += 1 sleep(1)
|
执行结果
The end
总的来说写这个的时候让自己python各种不足暴露出来,心酸满满,收获满满。
同时还可以用pyinstaller进行打包。Github下载链接
百度盘下载地址 提取码:ellb