爬虫实战(一):爬酷我音乐
前言
此方法仅供学习爬虫,切勿用在其他途径
要使用的库
模块
import requests, os, time, loguru import pandas as pd from concurrent.futures import ThreadPoolExecutor
分析
搜索分析
首先,我们搜索晴天这首歌
通过浏览器的抓包工具可得到,url = "http://kuwo.cn/api/www/search/searchMusicBykeyWord?key=%E6%99%B4%E5%A4%A9&pn=1&rn=30&httpsStatus=1&reqId=162909a0-78d8-11ec-b238-fdbe74073c65"
其中,“%E6%99%B4%E5%A4%A9”这为晴天的url编码
那我们进一步分析,那个key携带的值,是不是我们要搜索的值呢?
;pn,按照常量,我们猜测,其为页数;rn,我们猜测其为一页显示的数量,注意rid可以直接忽略,其为没有用处的随机值
那么如果我们,吧那个key的值换成一个歌手,再修改pn的值,我们是不是可以下载那名歌手的全部的歌曲呢?

打开其响应,可以得到:id = MUSIC_80456317

主页分析
然后,我们进入音乐主页
通过抓包工具。可以发现

分析其响应可得

然后我们访问那个地址,可以发现,那就是我们的歌曲存放的地址
通过主页分析,我们可以的到存储音乐url的接口,以及得到这个接口的方式
musicrid = "MUSIC_80456317".split("_")[-1] # _后面的数字即为url_api的mid url_api = f"http://kuwo.cn/api/v1/www/music/playUrl?mid={musicrid}&type=convert_url&httpsStatus=1" # 同时,可以得到musicrid的链接为 name = input("请输入歌曲名称/歌手名字:") page = input("请输入要下载的页数:") url_get_mid = f"http://kuwo.cn/api/www/search/searchMusicBykeyWord?key={name}&pn={page}&rn=30&httpsStatus=1"
分析完毕,上代码
代码
得到mid
def get_mid(url): # 得到歌曲的mid headers = { # 传入必要请求头,反爬 "Accept": "application/json, text/plain, */*", "Accept-Encoding": "gzip, deflate", "Accept-Language": "zh-CN,zh;q=0.9", "Connection": "keep-alive", "Cookie": "_ga=GA1.2.2058800930.1642474837; _gid=GA1.2.1174281146.1642474837; Hm_lvt_cdb524f42f0ce19b169a8071123a4797=1642490265,1642490289,1642490402,1642498818; Hm_lpvt_cdb524f42f0ce19b169a8071123a4797=1642499234; kw_token=YK4UZW2UPL", "csrf": "YK4UZW2UPL", "Host": "www.kuwo.cn", "Referer": "http://www.kuwo.cn/", "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.93 Safari/537.36", } resp = requests.get(url=url, headers=headers).json() content = resp["data"]["list"] content_lis = [] for i in content: mid = i["musicrid"].split("_")[-1] atr = i["artist"] names = i["name"] content_lis.append({"编号": mid, "歌名": names, "歌手": atr}) return content_lis
界面
def show_menu_song(df, data): # 得到选择要下载的歌曲,UI展示,选择要下载的歌曲 print("*************************************************") print("******** 这里找到了30首歌,请选择下载一首或多首 ********") while True: choice = input("******* 请输入编号(如果有多个编号请用空格分开)*********\n").split() temp = [i for i in choice if i in list(df.index)] if temp: choice1 = [] for i in data: if i["编号"] in choice: choice1.append({"name": f"{i['歌手']}", "mid": f"{i['编号']}"}) # 返回字典,便于索引 print("正在准备下载,请稍等!") return choice1 else: for i in choice: if i not in choice: print(f"没有编号:{i}") print("请重新输入!") def main1(): # 按照歌名下载 print("*************************************************") name = input("************* 请输入您想要下载的歌曲*****************\n") print("*************************************************") url = f"http://www.kuwo.cn/api/www/search/searchMusicBykeyWord?key={name}&pn=1&rn=30&httpsStatus=1" data = get_mid(url) # 通过调用函数的到mid df = pd.DataFrame(data).set_index("编号") print(df) choice = show_menu_song(df, data) # 存储的是歌曲的编号 url_api = [f"http://www.kuwo.cn/api/v1/www/music/playUrl?mid={i['mid']}&type=convert_url&httpsStatus=1" for i in choice] # 使用列表生成式快速生成url_api url_name = [f"{name}_{choice[i]['name']}" for i in range(len(url_api))] url_list = [] # 存储名字和url for i in range(len(url_api)): url_list.append({"name": url_name[i], "url": url_api[i]}) # 以键值对的方式存储,便于命名 return url_list # 返回结果 def main2(): # 按照歌手名字下载 print("*************************************************") name = input("************** 请输入歌手名字 *****************\n") while True: page = input("******* 请输入要下载的页数,一页30首歌 ***********\n") if 0 < eval(page) < 10 and isinstance(eval(page), int): # 一般9页,210首歌应该足够,防止输入页数过多,造成程序奔溃 break else: print("请输入1到10的数字") # 防止随便输入,提高程序的可用性 print("*************************************************") url = f"http://www.kuwo.cn/api/www/search/searchMusicBykeyWord?key={name}&pn={page}&rn=30&httpsStatus=1" data = get_mid(url) # 得到mid url_list = [] # 存放url for i in data: url_list.append({"name": i["歌名"], "url": f'http://www.kuwo.cn/api/v1/www/music/playUrl?mid={i["编号"]}&type=convert_url&httpsStatus=1'}) return url_list def main(): while True: # 界面展示,供自己选择 print("*************************************************") print("***************注意,不要下载太频繁******************") print("*************************************************") choice = input("*****根据歌手名字下载音乐还是歌名?1(歌名)/2(歌手)*******\n") print("*************************************************") if choice == "1": return main1() elif choice == "2": return main2() else: print("请按要求输入!")
下载
def download(url_dic): # 下载音乐 headers1 = { # 得到音乐下载地址的请求头 "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9", "Accept-Encoding": "gzip, deflate", "Accept-Language": "zh-CN,zh;q=0.9", "Cache-Control": "max-age=0", "Connection": "keep-alive", "Cookie": "_ga=GA1.2.2058800930.1642474837; _gid=GA1.2.1174281146.1642474837; Hm_lvt_cdb524f42f0ce19b169a8071123a4797=1642509517,1642511738,1642514710,1642551220; Hm_lpvt_cdb524f42f0ce19b169a8071123a4797=1642551237; kw_token=GR2I2YW69IE", "Host": "www.kuwo.cn", "Upgrade-Insecure-Requests": "1", "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.93 Safari/537.36", } resp = requests.get(url=url_dic["url"], headers=headers1).json() dl = resp["data"]["url"] # 得到的歌曲url time.sleep(1) print(dl, "\n如果没有这首歌,则可以通过这个链接下载") time.sleep(1) resp = requests.get(url=dl) if resp.status_code == 200: # 判断访问是否成功,如果失败则直接退出,避免报错 rp = resp.content try: # 判断有没有D盘和E盘 if not os.path.exists('e:/music'): os.mkdir("e:/music") with open(f"e:/music/{url_dic['name']}.mp3", "wb") as f: f.write(rp) loguru.logger.info(f"{url_dic['name']}下载完成") print("保存的歌曲在e盘的music文件夹里面") except: if not os.path.exists('d:/music'): os.mkdir("d:/music") with open(f"d:/music/{url_dic['name']}.mp3", "wb") as f: f.write(rp) loguru.logger.info(f"{url_dic['name']}下载完成") print("保存的歌曲在d盘的music文件夹里面") else: print("访问失败")
启动
if __name__ == '__main__': with ThreadPoolExecutor(50) as pol: # 使用线程池开启下载 pol.map(download, main()) time.sleep(5)
总代码
import requests, os, time, loguru import pandas as pd from concurrent.futures import ThreadPoolExecutor def get_mid(url): # 得到歌曲的mid headers = { # 传入必要请求头,反爬 "Accept": "application/json, text/plain, */*", "Accept-Encoding": "gzip, deflate", "Accept-Language": "zh-CN,zh;q=0.9", "Connection": "keep-alive", "Cookie": "_ga=GA1.2.2058800930.1642474837; _gid=GA1.2.1174281146.1642474837; Hm_lvt_cdb524f42f0ce19b169a8071123a4797=1642490265,1642490289,1642490402,1642498818; Hm_lpvt_cdb524f42f0ce19b169a8071123a4797=1642499234; kw_token=YK4UZW2UPL", "csrf": "YK4UZW2UPL", "Host": "www.kuwo.cn", "Referer": "http://www.kuwo.cn/", "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.93 Safari/537.36", } resp = requests.get(url=url, headers=headers).json() content = resp["data"]["list"] content_lis = [] for i in content: mid = i["musicrid"].split("_")[-1] atr = i["artist"] names = i["name"] content_lis.append({"编号": mid, "歌名": names, "歌手": atr}) return content_lis def download(url_dic): # 下载音乐 headers1 = { # 得到音乐下载地址的请求头 "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9", "Accept-Encoding": "gzip, deflate", "Accept-Language": "zh-CN,zh;q=0.9", "Cache-Control": "max-age=0", "Connection": "keep-alive", "Cookie": "_ga=GA1.2.2058800930.1642474837; _gid=GA1.2.1174281146.1642474837; Hm_lvt_cdb524f42f0ce19b169a8071123a4797=1642509517,1642511738,1642514710,1642551220; Hm_lpvt_cdb524f42f0ce19b169a8071123a4797=1642551237; kw_token=GR2I2YW69IE", "Host": "www.kuwo.cn", "Upgrade-Insecure-Requests": "1", "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.93 Safari/537.36", } resp = requests.get(url=url_dic["url"], headers=headers1).json() dl = resp["data"]["url"] # 得到的歌曲url time.sleep(1) print(dl, "\n如果没有这首歌,则可以通过这个链接下载") time.sleep(1) resp = requests.get(url=dl) if resp.status_code == 200: # 判断访问是否成功,如果失败则直接退出,避免报错 rp = resp.content try: # 判断有没有D盘和E盘 if not os.path.exists('e:/music'): os.mkdir("e:/music") with open(f"e:/music/{url_dic['name']}.mp3", "wb") as f: f.write(rp) loguru.logger.info(f"{url_dic['name']}下载完成") print("保存的歌曲在e盘的music文件夹里面") except: if not os.path.exists('d:/music'): os.mkdir("d:/music") with open(f"d:/music/{url_dic['name']}.mp3", "wb") as f: f.write(rp) loguru.logger.info(f"{url_dic['name']}下载完成") print("保存的歌曲在d盘的music文件夹里面") else: print("访问失败") def show_menu_song(df, data): # 得到选择要下载的歌曲,UI展示,选择要下载的歌曲 print("*************************************************") print("******** 这里找到了30首歌,请选择下载一首或多首 ********") while True: choice = input("******* 请输入编号(如果有多个编号请用空格分开)*********\n").split() temp = [i for i in choice if i in list(df.index)] if temp: choice1 = [] for i in data: if i["编号"] in choice: choice1.append({"name": f"{i['歌手']}", "mid": f"{i['编号']}"}) # 返回字典,便于索引 print("正在准备下载,请稍等!") return choice1 else: for i in choice: if i not in choice: print(f"没有编号:{i}") print("请重新输入!") def main1(): # 按照歌名下载 print("*************************************************") name = input("************* 请输入您想要下载的歌曲*****************\n") print("*************************************************") url = f"http://www.kuwo.cn/api/www/search/searchMusicBykeyWord?key={name}&pn=1&rn=30&httpsStatus=1" data = get_mid(url) # 通过调用函数的到mid df = pd.DataFrame(data).set_index("编号") print(df) choice = show_menu_song(df, data) # 存储的是歌曲的编号 url_api = [f"http://www.kuwo.cn/api/v1/www/music/playUrl?mid={i['mid']}&type=convert_url&httpsStatus=1" for i in choice] # 使用列表生成式快速生成url_api url_name = [f"{name}_{choice[i]['name']}" for i in range(len(url_api))] url_list = [] # 存储名字和url for i in range(len(url_api)): url_list.append({"name": url_name[i], "url": url_api[i]}) # 以键值对的方式存储,便于命名 return url_list # 返回结果 def main2(): # 按照歌手名字下载 print("*************************************************") name = input("************** 请输入歌手名字 *****************\n") while True: page = input("******* 请输入要下载的页数,一页30首歌 ***********\n") if 0 < eval(page) < 10 and isinstance(eval(page), int): # 一般9页,210首歌应该足够,防止输入页数过多,造成程序奔溃 break else: print("请输入1到10的数字") # 防止随便输入,提高程序的可用性 print("*************************************************") url = f"http://www.kuwo.cn/api/www/search/searchMusicBykeyWord?key={name}&pn={page}&rn=30&httpsStatus=1" data = get_mid(url) # 得到mid url_list = [] # 存放url for i in data: url_list.append({"name": i["歌名"], "url": f'http://www.kuwo.cn/api/v1/www/music/playUrl?mid={i["编号"]}&type=convert_url&httpsStatus=1'}) return url_list def main(): while True: # 界面展示,供自己选择 print("*************************************************") print("***************注意,不要下载太频繁******************") print("*************************************************") choice = input("*****根据歌手名字下载音乐还是歌名?1(歌名)/2(歌手)*******\n") print("*************************************************") if choice == "1": return main1() elif choice == "2": return main2() else: print("请按要求输入!") if __name__ == '__main__': with ThreadPoolExecutor(50) as pol: # 使用线程池开启下载 pol.map(download, main()) time.sleep(5)
注意
本案例只供学习,切勿他用
本文来自博客园,作者:Kenny_LZK,转载请注明原文链接:https://www.cnblogs.com/liuzhongkun/p/15821803.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了