介绍你是不是经常想在各大音乐网站下载音乐?但是网站强迫您下载他们的应用程序?然而,你下载app,他们却强制你买vip……没关系,今天我们就用爬虫来“制裁”这些网站!先从最简单的酷狗音乐开始攀登吧!功能概述让用户输入要搜索的音乐的名称,然后将所有的音乐以及每首音乐对应的信息显示给用户。然后询问用户是否要下载任何音乐。如果有,让用户输入音乐对应的id号下载(支持批量下载)。找出思路首先,在获取多首歌曲的信息和下载地址之前,我们需要知道如何获取一首歌曲的下载地址。打开酷狗网,在搜索栏中输入要查找的歌曲名称。按回车。切换网页后,点击进入歌曲播放页面。按F12调出开发人员工具。选择网络,然后单击全部。如您所见,当前没有显示任何内容。因为在打开开发者工具的时候已经加载了所有的文件,此时只需要按F5刷新网页即可。好的,现在你应该看到这样一个页面。能不能看到什么js文件,png文件,音频文件,一个都没有!因为在我们调用开发者工具之前网站已经加载了文件,此时我们只需要按F5刷新网站即可。好的,所有文件都已加载。输入一个名为index.php?的文件,然后输入这个文件的地址,输入文件地址后,这其实就是音乐信息(为了方便,文末就说是信息地址)。我们还可以看到一个叫做play_url的东西。这个play_url就是音频mp3文件的地址。可以看到这些play_urls都把/变成了\/。这个我们不用担心,因为URL输入框会自动为我们调整为/,但是在用代码实现爬虫的时候,我们需要把\/改成/。但在短时间内,我们并不关心这个。让我们转到这个URL,嗯?那不是我们刚刚播放的音乐吗?成功后,我们有更大的信心和想法去爬行。我们只需要找出每首歌曲的信息地址,然后用正则表达式就可以得到每首歌曲的信息和音乐地址。再次使用爬虫获取音乐的二进制码保存在本地。那么我们如何获取每首歌曲的信息地址呢?通过拼接地址!看看这两首歌的url有什么区别,你就知道了。Faded-https://wwwapi.kugou.com/yy/i...Calories-https://wwwapi.kugou.com/yy/i...可以看到hash值以外的东西,没有区别向上。也就是说,我们只需要通过https://wwwapi.kugou.com/yy/i拼接出每首歌曲的信息地址。。。歌曲的hash应该去哪里找呢?返回酷狗的音乐搜索栏,搜索歌曲并回车。你可以看到这里有很多歌曲。F12-NETWORK-ALL-F5,我们找到一个这样的文件。我们输入这个网址,就可以看到刚才所有歌曲的hash。那么问题又来了,我们如何获取这个哈希信息URL呢?这个太简单了,就是通过https://songsearch.kugou.com/...拼接url。对于搜索到的歌名,我们的代码使用input让用户输入歌名。那么,你找到方法了吗?思路:拼接出hash信息url,用正则表达式得到所有歌曲的hash,然后拼接出单首歌的url。最后再次使用正则表达式获取歌曲的play_url。开始写代码先导入我们的requests和re正则表达式库。re用于查找音乐的信息和下载地址,requests负责获取文本和下载音乐。importrequestsimportre我们还需要设置一些变量,后面会派上用场。timer=0song_urls={}names={}我们不是要把多首歌曲的信息url拼接出来吗?那么我们首先需要让用户输入歌曲名称。然后再战。songs=input("请输入歌曲名称:")url='https://songsearch.kugou.com/song_search_v2?callback=jQuery112409090559630919017_1585358668138&keyword=%s&page=1&pagesize=30&userid=-1&clientver=&platform=WebFilter_filter&tag=em&privilegefilter1&tag&2=0&_=1585358668140'%songs现在,我们可以使用请求来请求文本了!由于这个URL是一个get请求,而我们请求的是文本,所以我们也使用方法requests.get().text方法。texts=requests.get(url).text接下来,您可以尝试打印文本。打印出来的文字和我们拼接的url内容没有区别(我这里就不打印了,等python卡死就完了)。在这些文本中,我们可以获得每首歌曲的哈希值。用正则表达式找到它。song_hashes=re.findall('"FileHash":"(.*?)"',texts)打印song_hashes,可以看到是一个列表。所以我们要做一个for遍历。foriinsong_hashes:information_url='https://wwwapi.kugou.com/yy/index.php?r=play/getdata&callback=jQuery19104610954889760035_1585364074033&hash=%s&album_id=0&dfid=2SSGs60RKO9P0bAzIe0xF4Us&mid=5a959954d2f99fc1438fe2efb7596511&platid=4&_=1585364074034'%iinformation=requests.get(information_url).textsong_url=re.findall('"play_url":"(.*?)"',information)song_names=bytes(re.findall('"audio_name":"(.*?)"',information)[0],encoding='ascii').decode('unicode-escape')singers=bytes(re.findall('"author_name":"(.*?)"',information)[0],encoding='ascii').decode('unicode-escape')如果song_names不在names.values()中:names[str(timer)]=song_namesprint("%d.%s"%(timer,song_names))print("Author:%s"%singers)print()timer+=1ifsong_url[0]notinsong_urls.values():song_urls[str(timer-1)]=song_url[0]在上面的代码中,我们对每一个hash进行了拼接操作,然后我们从单曲的信息文本中找到了音乐名称、作者和下载地址song.由于音乐名称和作者是ascii编码的,我们还需要进行解码。由于有时会重复打印歌名和歌手,因此每次打印音乐和作者时,我们都会将音乐和作者姓名添加到字典中。每次打印都会判断是否有字典。字典的键随着我们的定时器变量的改变而改变。此外,我们还在song_urls字典中保存了每首歌曲的下载地址。打印音乐信息后,需要询问用户下载哪首歌。print('输入n不会下载,如果要下载多首歌曲,请用英文符号“,”隔开')choice=input('请输入要下载的歌曲编号:').split(',')ifchoice=="n":exit()else:path=input("请输入要保存的路径:")foriinchoice:song_url=song_urls[i].replace('\\/','/')song=requests.get(song_url).contentsave_name=names[i]withopen(path+'/'+save_name+'.mp3','wb')asf:f.write(歌曲)print("savecompleted!")按照之前的做法,使用requests.get().content将音乐转换为二进制文件,然后保存。在获取之前,我们还需要把乱七八糟的URL的\/改成/。之后,您可以保存它!我们拿一首歌叫《你走的那一天》来试试代码实现效果:程序不足。酷狗每隔一段时间就会制作一个滑动验证码。这个时候我们的程序是获取不到数据的。这种情况用selenium可以轻松解决。完整代码:#导入库importrequestsimportreimportos#设置一些变量timer=0#设置一台计算歌曲顺序的机器song_urls={}names={}songs=input("请输入歌曲名称:")url='https://songsearch.kugou.com/song_search_v2?callback=jQuery112409090559630919017_1585358668138&keyword=%s&page=1&pagesize=30&userid=-1&clientver=&platform=WebFilter&tag=em&filter=2&iscorrection=1&privilege_filter=0&_=1585358668140'%songstexts=requests.get(url).textsong_hashes=re.findall('"FileHash":"(.*?)"',texts)print("请稍等...")foriinsong_hashes:information_url='https://wwwapi.kugou.com/yy/index.php?r=play/getdata&callback=jQuery19104610954889760035_1585364074033&hash=%s&album_id=0&dfid=2SSGs60RKO9P0bAzIe0xF4Us&mid=5a959954d2f99fc1438fe2efb7596511&platid=4&_=1585364074034'%iinformation=requests.get(information_url).textsong_url=re.findall('"play_url":"(.*?)"',信息)song_names=bytes(re.findall('"audio_name":"(.*?)"',information)[0],encoding='ascii').decode('unicode-escape')singers=bytes(re.findall('"author_name":"(.*?)"',information)[0],encoding='ascii').decode('unicode-escape')如果song_names不在names.values():names[str(timer)]=song_namesprint("%d.%s"%(timer,song_names))print("Author:%s"%singers)print()timer+=1如果song_url[0]不在song_urls.values()中:song_urls[str(timer-1)]=song_url[0]print('输入n停止下载,如果要下载多首歌曲,请用英文符号“,”分隔')choice=input('请输入要下载的歌曲编号:').split(',')ifchoice=="n":exit()else:path=input("请输入要保存的路径:")has_path=os.path.exists(path)whilehas_path==False:print("路径确实不存在!!")path=input("请输入保存路径:")has_path=os.path.exists(path)foriinchoice:song_url=song_urls[i].replace('\\/','/')song=requests.get(song_url).contentsave_name=names[i]withopen(path+'/'+save_name+'.mp3','wb')asf:f.write(song)print("保存完成!")
