当前位置:   article > 正文

python爬虫项目实战: 爬取酷狗音乐详细操作_酷狗音乐榜爬虫python

酷狗音乐榜爬虫python

目标

主要目的为爬取酷狗音乐网站 mp3 任意音乐数据,并将爬取后的mp3数据保存为以.mp3后缀的音频文件

所用模块

hashlib => md5加密:提供了许多加密哈希算法,包括MD5、SHA-1、SHA-256等。
os      => 提供了访问操作系统功能的方法,例如文件操作、目录操作、进程管理等。
time    => 提供了处理时间的函数,包括获取当前时间、延时等功能。
requests=> 用于发送HTTP请求和处理响应。
re      => 提供了正则表达式操作的函数,用于在字符串中搜索、匹配和替换文本。
json    => 用于处理JSON数据,用于JSON格式转换。
tkinter => 提供了创建图形用户界面(GUI)的工具包,可以用于构建窗口、按钮、文本框等GUI元素。

基本思路

一 :音乐获取

打开浏览器,进入酷狗音乐网页,点击F12进入开发者模式

 点击上面一栏的媒体,可以看到mp3音乐文件

 可以发现这个文件就是当前音乐mp3媒体文件,但是我们需要找到它的来源处,可以在搜索出直接搜索横线那部分

 对比一下我们可以发现,我们所需要的mp3文件来源于此处。且位于play_url参数中,因此我们现在需要的就是爬取当前此文件。

 所以,我们先确定它的url。通过对比url与字符串参数发现,网页url只为“https://wwwapi.kugou.com/play/songinfo?”,其余都只是参数。

我们再取对比其他音乐的当前地址,发现他们只有“clienttime”,"encode","signature"这几个参数有变化。因此,我们可以知道,在爬取其他音乐时我们也只是需要改这几个参数便可以。

其中,发现“clienttime”为时间戳,"encode"为音乐ID,"signature"为md5加密的参数所以,我们只需要解密'signature'此参数,我们可以通过Ctrl+Swift+f打开全局搜索,搜索'signature',发现signature参数来与此js中,我们可以点击进入js查看

进入此处,我们在signature所需要的参数此行点击打上断电,并刷新页面。鼠标选中参数详细。会发现,此处就是我们所需要的参数。32位字母数字组合。再去查看它组合方式,就会发现它就是s的参数列表,转换成字符串直接用md5加密便可。而再通过对比一下s发现它的参数除了时间戳和音乐id完全一样,因此我们可以自己组合

而后组合加密得出signature参数,便可通过改变音乐id直接请求当前音乐的MP3信息。

二: 搜索指定获取

简单描述此操作 就是输入你想要的 音乐名 或 音乐名加作者名 搜索到音乐,获取 音乐ID 交给
第一步操作获得音乐mp3文件

我们现在需要模拟酷狗搜索栏操作,通过关键字搜索,并获取与关键字最相识的第一个音乐。

继续之前的操作,F12进入,并在左上角点击搜索按钮,搜索当前音乐名,点击进入。并进行对比发现song就是我们需要的数据

进入之后,我们会发现,搜索的所有的音乐内容都在lists中,我们只需要第一条的音乐内容,
并获取此音乐的ID与名字

再通过对比参数中signature发现和之前参数区别一样。因此,复制之前的操作便可

具体的步骤为同样搜索signature找到其js文件,打上断点调试,复制第一步的操作,得到signature参数,加入需要请求的url地址中“https://complexsearch.kugou.com/v2/search/song?”,便可得到搜索的音乐id  "EAlbumID"。将其给到第一步id中运行,便可以得到想要的音乐mp3数据。

三: 保存为mp3文件

获取到此音频地址后,对地址发送请求,将请求得到的数据以二进制的方式保存到指定目录文件夹中

代码部分

用到的模块
  1. import hashlib
  2. import os
  3. import time
  4. import requests
  5. import re
  6. import json
  7. from tkinter import *
判断文件是否存在。不存在则创建改文件。        
此文件为获取后保存的文件
  1. def directory_create():
  2. """判断文件是否存在。不存在则创建改文件"""
  3. directory = "./music_files"
  4. if not os.path.exists(directory):
  5. os.makedirs(directory)
通过搜索栏参数(音乐名)获取 搜索第一个的 音乐名 和 音乐id。  也就是第二个步骤(搜索指定获取)操作。
  1. def audio_id_list(music_name):
  2. """
  3. 通过搜索栏参数(音乐名)获取 搜索第一个的 音乐名 and ID
  4. :param music_name: 搜索栏参数(音乐名) 例如: 苏星婕 - 把回忆拼好给你
  5. :return: 音乐名 音乐ID(苏星婕 - 把回忆拼好给你 72jrv7fa)
  6. """
  7. timestamp = int(time.time() * 1000)
  8. headers = {
  9. 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36',
  10. }
  11. sign = MD5_sign_search(timestamp, music_name)
  12. datas = {
  13. 'callback': 'callback123',
  14. 'srcappid': '2919',
  15. 'clientver': '1000',
  16. 'clienttime': timestamp,
  17. 'mid': 'c4de83c1ebb2e73fc5ae95304a674918',
  18. 'uuid': 'c4de83c1ebb2e73fc5ae95304a674918',
  19. 'dfid': '3MmrUf3e5zpy3cStkN3Bn9oS',
  20. 'keyword': music_name,
  21. 'page': '1',
  22. 'pagesize': '30',
  23. 'bitrate': '0',
  24. 'isfuzzy': '0',
  25. 'inputtype': '0',
  26. 'platform': 'WebFilter',
  27. 'userid': '2078452878',
  28. 'iscorrection': '1',
  29. 'privilege_filter': '0',
  30. 'filter': '10',
  31. 'token': '483ef68936faa09268f3a42f7ab7ee31b584a3f155828a100c95fadf7c5ddd1e',
  32. 'appid': '1014',
  33. 'signature': sign,
  34. }
  35. response = requests.get(url='https://complexsearch.kugou.com/v2/search/song?', headers=headers, params=datas)
  36. callback_dict = re.findall('callback123\((.*)\)', response.text)[0]
  37. jsurl = json.loads(callback_dict)
  38. fileName = jsurl['data']['lists'][0]['FileName']
  39. eMixSongID = jsurl['data']['lists'][0]['EMixSongID']
  40. return fileName, eMixSongID
通过音乐ID爬取当前音乐的md3地址。也就是第一个操作部分(音乐获取)
  1. def fetch_url(audio_id):
  2. """
  3. 通过音乐ID爬取当前音乐的md3地址
  4. :param audio_id: 音乐ID(72jrv7fa)
  5. :return:音乐url(........mp3)
  6. """
  7. timestamp = int(time.time() * 1000)
  8. print('audio_id:', audio_id)
  9. headers = {
  10. 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36',
  11. }
  12. sign = MD5_sign(timestamp, audio_id)
  13. datas = {
  14. 'srcappid': '2919',
  15. 'clientver': '20000',
  16. 'clienttime': timestamp,
  17. 'mid': 'c4de83c1ebb2e73fc5ae95304a674918',
  18. 'uuid': 'c4de83c1ebb2e73fc5ae95304a674918',
  19. 'dfid': '3MmrUf3e5zpy3cStkN3Bn9oS',
  20. 'appid': '1014',
  21. 'platid': '4',
  22. 'encode_album_audio_id': audio_id,
  23. 'token': '483ef68936faa09268f3a42f7ab7ee31b584a3f155828a100c95fadf7c5ddd1e',
  24. 'userid': '2078452878',
  25. 'signature': sign,
  26. }
  27. response = requests.get(url='https://wwwapi.kugou.com/play/songinfo?', headers=headers, params=datas)
  28. jsurl = response.json()
  29. # print('jsurl: ', jsurl)
  30. play_url = jsurl['data']['play_url']
  31. return play_url
获取到此音频地址后,对地址发送请求,将请求得到的数据以二进制的方式保存到指定目录文件夹中。
  1. def download_url(file_name, url_mp3):
  2. """
  3. 通过已经获取的mp3文件保存到文件夹中
  4. :param file_name: 音乐名
  5. :param url_mp3: 音乐url(.....mp3)
  6. :return: 无
  7. """
  8. response = requests.get(url_mp3)
  9. try:
  10. with open(f"./music_files/{file_name}.mp3", "wb") as f:
  11. f.write(response.content)
  12. except:
  13. with open(f"./music_files/{int(time.time() * 1000)}.mp3", "wb") as f:
  14. f.write(response.content)
  15. print(f'{file_name}-----下载成功')
搜索页面和播放页面的两个signature的解密操作:MD5加密
  1. def MD5_sign(timestamp, audio_id):
  2. """
  3. 通过音乐id解密详情页单个音乐的signature参数
  4. :param timestamp: 时间戳
  5. :param audio_id: 音乐id(例如:72jrv7fa)
  6. :return:
  7. """
  8. signature_list = ['NVPh5oo715z5DIWAeQlhMDsWXXQV4hwt',
  9. 'appid=1014',
  10. f'clienttime={timestamp}',
  11. 'clientver=20000',
  12. 'dfid=3MmrUf3e5zpy3cStkN3Bn9oS',
  13. f'encode_album_audio_id={audio_id}',
  14. 'mid=c4de83c1ebb2e73fc5ae95304a674918',
  15. 'platid=4',
  16. 'srcappid=2919',
  17. 'token=483ef68936faa09268f3a42f7ab7ee31b584a3f155828a100c95fadf7c5ddd1e',
  18. 'userid=2078452878',
  19. 'uuid=c4de83c1ebb2e73fc5ae95304a674918',
  20. 'NVPh5oo715z5DIWAeQlhMDsWXXQV4hwt']
  21. string = "".join(signature_list)
  22. MD5 = hashlib.md5()
  23. MD5.update(string.encode('utf-8'))
  24. sign = MD5.hexdigest() # md5 32位加密内容
  25. return sign
  26. def MD5_sign_search(timestamp, music_name):
  27. """
  28. 通过音乐id解密搜索页的signature参数
  29. :param timestamp:时间戳
  30. :param music_name:搜索框音乐名(例如:把回忆拼好给你)
  31. :return:加密后32位md5参数(例如:72181cc6baf76ee0404837d5d657dd5c)
  32. """
  33. signature_list = ['NVPh5oo715z5DIWAeQlhMDsWXXQV4hwt',
  34. 'appid=1014',
  35. 'bitrate=0',
  36. 'callback=callback123',
  37. f'clienttime={timestamp}',
  38. 'clientver=1000',
  39. 'dfid=3MmrUf3e5zpy3cStkN3Bn9oS',
  40. 'filter=10',
  41. 'inputtype=0',
  42. 'iscorrection=1',
  43. 'isfuzzy=0',
  44. f'keyword={music_name}',
  45. 'mid=c4de83c1ebb2e73fc5ae95304a674918',
  46. 'page=1',
  47. 'pagesize=30',
  48. 'platform=WebFilter',
  49. 'privilege_filter=0',
  50. 'srcappid=2919',
  51. 'token=483ef68936faa09268f3a42f7ab7ee31b584a3f155828a100c95fadf7c5ddd1e',
  52. 'userid=2078452878',
  53. 'uuid=c4de83c1ebb2e73fc5ae95304a674918',
  54. 'NVPh5oo715z5DIWAeQlhMDsWXXQV4hwt']
  55. string = "".join(signature_list)
  56. MD5 = hashlib.md5()
  57. MD5.update(string.encode('utf-8'))
  58. sign_lis = MD5.hexdigest() # md5 32位加密内容
  59. return sign_lis

总代码

总结

  1. import hashlib
  2. import os
  3. import time
  4. import requests
  5. import re
  6. import json
  7. from tkinter import *
  8. def MD5_sign(timestamp, audio_id):
  9. """
  10. 通过音乐id解密详情页单个音乐的signature参数
  11. :param timestamp: 时间戳
  12. :param audio_id: 音乐id(例如:72jrv7fa)
  13. :return:
  14. """
  15. signature_list = ['NVPh5oo715z5DIWAeQlhMDsWXXQV4hwt',
  16. 'appid=1014',
  17. f'clienttime={timestamp}',
  18. 'clientver=20000',
  19. 'dfid=3MmrUf3e5zpy3cStkN3Bn9oS',
  20. f'encode_album_audio_id={audio_id}',
  21. 'mid=c4de83c1ebb2e73fc5ae95304a674918',
  22. 'platid=4',
  23. 'srcappid=2919',
  24. 'token=483ef68936faa09268f3a42f7ab7ee31b584a3f155828a100c95fadf7c5ddd1e',
  25. 'userid=2078452878',
  26. 'uuid=c4de83c1ebb2e73fc5ae95304a674918',
  27. 'NVPh5oo715z5DIWAeQlhMDsWXXQV4hwt']
  28. string = "".join(signature_list)
  29. MD5 = hashlib.md5()
  30. MD5.update(string.encode('utf-8'))
  31. sign = MD5.hexdigest() # md5 32位加密内容
  32. return sign
  33. def MD5_sign_search(timestamp, music_name):
  34. """
  35. 通过音乐id解密搜索页的signature参数
  36. :param timestamp:时间戳
  37. :param music_name:搜索框音乐名(例如:把回忆拼好给你)
  38. :return:加密后32位md5参数(例如:72181cc6baf76ee0404837d5d657dd5c)
  39. """
  40. signature_list = ['NVPh5oo715z5DIWAeQlhMDsWXXQV4hwt',
  41. 'appid=1014',
  42. 'bitrate=0',
  43. 'callback=callback123',
  44. f'clienttime={timestamp}',
  45. 'clientver=1000',
  46. 'dfid=3MmrUf3e5zpy3cStkN3Bn9oS',
  47. 'filter=10',
  48. 'inputtype=0',
  49. 'iscorrection=1',
  50. 'isfuzzy=0',
  51. f'keyword={music_name}',
  52. 'mid=c4de83c1ebb2e73fc5ae95304a674918',
  53. 'page=1',
  54. 'pagesize=30',
  55. 'platform=WebFilter',
  56. 'privilege_filter=0',
  57. 'srcappid=2919',
  58. 'token=483ef68936faa09268f3a42f7ab7ee31b584a3f155828a100c95fadf7c5ddd1e',
  59. 'userid=2078452878',
  60. 'uuid=c4de83c1ebb2e73fc5ae95304a674918',
  61. 'NVPh5oo715z5DIWAeQlhMDsWXXQV4hwt']
  62. string = "".join(signature_list)
  63. MD5 = hashlib.md5()
  64. MD5.update(string.encode('utf-8'))
  65. sign_lis = MD5.hexdigest() # md5 32位加密内容
  66. return sign_lis
  67. def fetch_url(audio_id):
  68. """
  69. 通过音乐ID爬取当前音乐的md3地址
  70. :param audio_id: 音乐ID(72jrv7fa)
  71. :return:音乐url(........mp3)
  72. """
  73. timestamp = int(time.time() * 1000)
  74. print('audio_id:', audio_id)
  75. headers = {
  76. 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36',
  77. }
  78. sign = MD5_sign(timestamp, audio_id)
  79. datas = {
  80. 'srcappid': '2919',
  81. 'clientver': '20000',
  82. 'clienttime': timestamp,
  83. 'mid': 'c4de83c1ebb2e73fc5ae95304a674918',
  84. 'uuid': 'c4de83c1ebb2e73fc5ae95304a674918',
  85. 'dfid': '3MmrUf3e5zpy3cStkN3Bn9oS',
  86. 'appid': '1014',
  87. 'platid': '4',
  88. 'encode_album_audio_id': audio_id,
  89. 'token': '483ef68936faa09268f3a42f7ab7ee31b584a3f155828a100c95fadf7c5ddd1e',
  90. 'userid': '2078452878',
  91. 'signature': sign,
  92. }
  93. response = requests.get(url='https://wwwapi.kugou.com/play/songinfo?', headers=headers, params=datas)
  94. jsurl = response.json()
  95. # print('jsurl: ', jsurl)
  96. play_url = jsurl['data']['play_url']
  97. return play_url
  98. def audio_id_list(music_name):
  99. """
  100. 通过搜索栏参数(音乐名)获取 搜索第一个的 音乐名 and ID
  101. :param music_name: 搜索栏参数(音乐名) 例如: 苏星婕 - 把回忆拼好给你
  102. :return: 音乐名 音乐ID(苏星婕 - 把回忆拼好给你 72jrv7fa)
  103. """
  104. timestamp = int(time.time() * 1000)
  105. headers = {
  106. 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36',
  107. }
  108. sign = MD5_sign_search(timestamp, music_name)
  109. datas = {
  110. 'callback': 'callback123',
  111. 'srcappid': '2919',
  112. 'clientver': '1000',
  113. 'clienttime': timestamp,
  114. 'mid': 'c4de83c1ebb2e73fc5ae95304a674918',
  115. 'uuid': 'c4de83c1ebb2e73fc5ae95304a674918',
  116. 'dfid': '3MmrUf3e5zpy3cStkN3Bn9oS',
  117. 'keyword': music_name,
  118. 'page': '1',
  119. 'pagesize': '30',
  120. 'bitrate': '0',
  121. 'isfuzzy': '0',
  122. 'inputtype': '0',
  123. 'platform': 'WebFilter',
  124. 'userid': '2078452878',
  125. 'iscorrection': '1',
  126. 'privilege_filter': '0',
  127. 'filter': '10',
  128. 'token': '483ef68936faa09268f3a42f7ab7ee31b584a3f155828a100c95fadf7c5ddd1e',
  129. 'appid': '1014',
  130. 'signature': sign,
  131. }
  132. response = requests.get(url='https://complexsearch.kugou.com/v2/search/song?', headers=headers, params=datas)
  133. callback_dict = re.findall('callback123\((.*)\)', response.text)[0]
  134. jsurl = json.loads(callback_dict)
  135. fileName = jsurl['data']['lists'][0]['FileName']
  136. eMixSongID = jsurl['data']['lists'][0]['EMixSongID']
  137. return fileName, eMixSongID
  138. def download_url(file_name, url_mp3):
  139. """
  140. 通过已经获取的mp3文件保存到文件夹中
  141. :param file_name: 音乐名
  142. :param url_mp3: 音乐url(.....mp3)
  143. :return: 无
  144. """
  145. response = requests.get(url_mp3)
  146. try:
  147. with open(f"./music_files/{file_name}.mp3", "wb") as f:
  148. f.write(response.content)
  149. except:
  150. with open(f"./music_files/{int(time.time() * 1000)}.mp3", "wb") as f:
  151. f.write(response.content)
  152. print(f'{file_name}-----下载成功')
  153. def directory_create():
  154. """判断文件是否存在。不存在则创建改文件"""
  155. directory = "./music_files"
  156. if not os.path.exists(directory):
  157. os.makedirs(directory)
  158. if __name__ == '__main__':
  159. directory_create() # 判断music_flie文件是否存在
  160. music_name = '听说你'
  161. audio_id = audio_id_list(music_name) # (苏星婕 - 把回忆拼好给你, 72jrv7fa)
  162. file_name = audio_id[0] # 苏星婕 - 把回忆拼好给你
  163. emixsong_id = audio_id[1] # 72jrv7fa
  164. time.sleep(2)
  165. url_mp3 = fetch_url(emixsong_id) # 获取 ......mp3
  166. download_url(file_name, url_mp3) # 下载保存

本次爬取结束,如果有什么其他问题或不懂可以私信哦~

另外还有GUI渲染过的的exe便携版,想要了解的话可以看下一篇文章

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/从前慢现在也慢/article/detail/608979
推荐阅读
相关标签
  

闽ICP备14008679号