Python爬取音乐,Python爬取酷狗音乐

  Python爬取音乐,Python爬取酷狗音乐

  本文主要介绍如何使用Python抓取酷炫的网络音乐。文章中的示例代码有详细的解释,感兴趣的朋友可以跟随边肖了解一下。

  00-1010前言获取歌曲信息列表请求参数分析请求代码获取歌曲下载链接免费歌曲付费歌曲请求代码附言

  

目录

  写这篇博客的初衷是加深我对发送和响应网络请求的理解。它仅用于学习目的。请不要用于非法目的!文明爬虫,从我做起。让我们言归正传。

  

前言

  在酷我的搜索框输入关键词aiko,输入就可以看到所有和aiko相关的歌曲。打开开发者模式,在网络面板下按ctrl f,搜索两个人,可以在响应结果中找到两个人的请求。该请求用于获得歌曲信息列表。

  

获取歌曲信息列表

  请求的具体格式如下图所示。您可以看到请求路径是http://www.kuwo.cn/api/www/search/searchMusicBykeyWord,请求参数包括:

  Key:搜索关键字,这里是aikopn:的页码,page number的缩写,这里是1rn:的每页条目数,应该是行号的缩写。默认为30httpsStatus的状态:https?我觉得用处不大。看完源代码我就写t.url=t.url ?Req=。concat (n, https status=1) Req ID:请求ID,该值将在页面刷新后更改。不知道有什么用。如果以后模拟要求的时候尽量不带他会怎么样?

  打开Apifox(当然邮差也可以),新建一个接口,设置请求路径和参数如下图所示。为了缩短响应时间,这里将每页的条目数设置为1,而不是默认的30:

  试着发送一个请求,不设置额外的请求头,我发现403禁止,emmmmm,应该是防盗链造成的:

  可以看到浏览器发送的请求的请求头中有一个设置Referer字段。如果您添加它,您应该不会再次报告错误:

  这一次,状态代码是200,但是没有收到任何数据。success为false,表示请求失败。消息表明失败原因是缺少CSRF令牌。问题不大。然后在浏览器发送的请求中添加csrf到Apifox请求头,然后发送请求,否则报错CSRF令牌无效!算了,还是老老实实把cookie加进去吧,但不是全部,只有kw_token=CCISYM2HV96部分,因为cookie里只有这个字段和token。

  /code>有关系且它的值和csrf相同。

  在源代码面板按下ctrl+shift+f,搜索一下csrf,可以看到csrf本来就是来自Object(h.b)("kw_token"),这个函数用来取出document.cookie中的kw_token字段值。至于 Cookie 中的kw_token怎么计算得到的,那就是服务器的事情了,咱们只管 CV 操作即可。

  

  准备好参数和请求头,重新发送请求,可以得到想要的数据。如果去掉reqId参数,也可以拿到数据,但是会有略微的不同,这里就不贴出来了:

  

{

   "code": 200,

   "curTime": 1649482287185,

   "data": {

   "total": "741",

   "list": [

   {

   "musicrid": "MUSIC_11690555",

   "barrage": "0",

   "ad_type": "",

   "artist": "aiko",

   "mvpayinfo": {

   "play": 0,

   "vid": 8530326,

   "down": 0

   },

   "nationid": "0",

   "pic": "http://img4.kuwo.cn/star/starheads/500/24/88/4146545084.jpg",

   "isstar": 0,

   "rid": 11690555,

   "duration": 362,

   "score100": "42",

   "ad_subtype": "0",

   "content_type": "0",

   "track": 1,

   "hasLossless": true,

   "hasmv": 1,

   "releaseDate": "1970-01-01",

   "album": "",

   "albumid": 0,

   "pay": "16515324",

   "artistid": 1907,

   "albumpic": "http://img4.kuwo.cn/star/starheads/500/24/88/4146545084.jpg",

   "originalsongtype": 0,

   "songTimeMinutes": "06:02",

   "isListenFee": false,

   "pic120": "http://img4.kuwo.cn/star/starheads/120/24/88/4146545084.jpg",

   "name": "恋をしたのは",

   "online": 1,

   "payInfo": {

   "play": "1100",

   "nplay": "00111",

   "overseas_nplay": "11111",

   "local_encrypt": "1",

   "limitfree": 0,

   "refrain_start": 89150,

   "feeType": {

   "song": "1",

   "vip": "1"

   },

   "down": "1111",

   "ndown": "11111",

   "download": "1111",

   "cannotDownload": 0,

   "overseas_ndown": "11111",

   "refrain_end": 126247,

   "cannotOnlinePlay": 0

   },

   "tme_musician_adtype": "0"

   }

   ]

   },

   "msg": "success",

   "profileId": "site",

   "reqId": "4b55cf4b0171253c33ce1d71b999c42f",

   "tId": ""

  }

  

  

  

  

请求代码

  响应结果的data字段中有很多东西,这里只提取需要的部分。在提取之前先来定义一下歌曲信息实体类,这样在其他函数中要一首歌曲的信息时只要把实体类的实例传入即可。

  

# coding:utf-8

  from copy import deepcopy

  from dataclasses import dataclass

  class Entity:

   """ Entity abstract class """

   def __setitem__(self, key, value):

   self.__dict__[key] = value

   def __getitem__(self, key):

   return self.__dict__[key]

   def get(self, key, default=None):

   return self.__dict__.get(key, default)

   def copy(self):

   return deepcopy(self)

  @dataclass

  class SongInfo(Entity):

   """ Song information """

   file: str = None

   title: str = None

   singer: str = None

   album: str = None

   year: int = None

   genre: str = None

   duration: int = None

   track: int = None

   trackTotal: int = None

   disc: int = None

   discTotal: int = None

   createTime: int = None

   modifiedTime: int = None

  

  上述代码显示定义了实体类的基类,并且重写了__getitem____setitem__魔法方法,这样我们可以像访问字典一样来访问实体类对象的属性。接着让歌曲信息实体类继承了实体类基类,并且使用@dataclass装饰器,这是 python 3.7 引入的新特性,使用它装饰之后的实体类无需实现构造函数、__str__等常用函数,python 会帮我们自动生成。

  在发送请求的过程中可能会遇到各种异常,如果在代码里面写try except语句会显得很乱,这里同样可以用装饰器来解决这个问题。

  

# coding:utf-8

  from copy import deepcopy

  def exceptionHandler(*default):

   """ decorator for exception handling

   Parameters

   ----------

   *default:

   the default value returned when an exception occurs

   """

   def outer(func):

   def inner(*args, **kwargs):

   try:

   return func(*args, **kwargs)

   except BaseException as e:

   print(e)

   value = deepcopy(default)

   if len(value) == 0:

   return None

   elif len(value) == 1:

   return value[0]

   else:

   return value

   return inner

   return outer

  

  下面是发送获取歌曲信息请求的代码,使用exception_handler装饰了getSongInfos方法,这样发生异常时会打印异常信息并返回默认值:

  

# coding:utf-8

  import json

  from urllib import parse

  from typing import List, Tuple

  import requests

  class KuWoMusicCrawler:

   """ Crawler of KuWo Music """

   def __init__(self):

   super().__init__()

   self.headers = {

   User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64)

   AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36,

   Cookie: kw_token=C713RK6IJ8J,

   csrf: C713RK6IJ8J,

   Host: www.kuwo.cn,

   Referer:

   }

   @exceptionHandler([], 0)

   def getSongInfos(self, key_word: str, page_num=1, page_size=10) -> Tuple[List[SongInfo], int]:

   key_word = parse.quote(key_word)

   # configure request header

   headers = self.headers.copy()

   headers["Referer"] = http://www.kuwo.cn/search/list?key=+key_word

   # send request for song information

   url = fhttp://www.kuwo.cn/api/www/search/searchMusicBykeyWord?key={key_word}&pn={page_num}&rn={page_size}&reqId=c06e0e50-fe7c-11eb-9998-47e7e13a7206

   response = requests.get(url, headers=headers)

   response.raise_for_status()

   # parse the response data

   song_infos = []

   data = json.loads(response.text)[data]

   for info in data[list]:

   song_info = SongInfo()

   song_info[rid] = info[rid]

   song_info.title = info[name]

   song_info.singer = info[artist]

   song_info.album = info[album]

   song_info.year = info[releaseDate].split(-)[0]

   song_info.track = info[track]

   song_info.trackTotal = info[track]

   song_info.duration = info["duration"]

   song_info.genre = Pop

   song_info[coverPath] = info.get(albumpic, )

   song_infos.append(song_info)

   return song_infos, int(data[total])

  

  

  

获取歌曲下载链接

  

  

免费歌曲

  虽然我们实现了搜索歌曲的功能,但是没拿到每一首歌的播放地址,也就没办法把歌曲下载下来。我们先来播放一首不收费的歌曲试试。可以看到浏览器发送了一个获取播放链接的请求,路径为http://www.kuwo.cn/api/v1/www/music/playUrl,有两个需要关注的参数:

  

  • mid:音乐 Id,此处的值为941583,和页面 url 中的编号一致,由于我们是通过点击搜索结果页面中二人跳转过来的,而二人这条结果也是动态加载出来的,超链接中的 Id 肯定也来自于上一节中响应结果的某个字段。二人是第四条记录,通过对比可以发现data.list[3].rid就是mid
  • type:音乐类型?此处的值为music,发送请求的时候也设置为music即可

  

  在 Apifox 中新建一个获取歌曲播放地址的请求,如下所示,发现可以成功拿到播放地址:

  

  

  

付费歌曲

  现在换一首歌,比如aiko - 横颜,点击歌曲页面上的播放按钮时会弹出要求在客户端中付费收听的对话框。直接发送请求,响应结果会是下面这个样子,状态码为 403:

  

  其实酷我在 2021 年 9 月份的时候换过获取播放地址的接口,那时候的请求接口为http://www.kuwo.cn/url,支持以下几个参数:

  

  • format: 在线音乐的格式,可以是mp3
  • type: 和现在的接口中的type参数一样,但是值为convert_url3
  • rid: 音乐 Id,和mid一样
  • br: 在线音乐的比特率,越大则音质越高,可选的有128kmp3192kmp3320kmp3

  这个接口不管是付费音乐还是免费音乐都可以用。如果将现在这个接口的type参数的值换成convert_url3,请求结果如下所示,说明成功了:

  

  

请求代码

  下面是获取在线音乐播放链接的代码,只需调用downloadSong函数并把爬取到的歌曲传入就能完成歌曲的下载:

  

@exceptionHandler()

  def getSongUrl(self, song_info: SongInfo) -> str:

   # configure request header

   headers = self.headers.copy()

   headers.pop(Referer)

   headers.pop(csrf)

   # send request for play url

   url = f"http://www.kuwo.cn/api/v1/www/music/playUrl?mid={song_info[rid]}&type=convert_url3"

   response = requests.get(url, headers=headers)

   response.raise_for_status()

   play_url = json.loads(response.text)[data][url]

   return play_url

  @exceptionHandler()

  def downloadSong(self, song_info: SongInfo, save_dir: str) -> str:

   # get play url

   url = self.getSongUrl(song_info)

   if not url:

   return

   # send request for binary data of audio

   headers = self.headers.copy()

   headers.pop(Referer)

   headers.pop(csrf)

   headers.pop(Host)

   response = requests.get(url, headers=headers)

   response.raise_for_status()

   # save audio file

   song_path = os.path.join(

   save_dir, f"{song_info.singer} - {song_info.title}.mp3")

   with open(song_path, wb) as f:

   f.write(data)

   return song

  

  

  

后记

  除了获取歌曲的详细信息和播放地址外,我们还能拿到歌词、歌手信息等,方法是类似的,在我的Groove中提供了在线歌曲的功能,一部分接口就是来自酷我,还有一些来自酷狗和网易云,爬虫的代码在app/common/crawler目录下,喜欢的话可以给个 star 哦,以上~~

  以上就是教你如何使Python爬取酷我在线音乐的详细内容,更多关于Python爬取音乐的资料请关注盛行IT软件开发工作室其它相关文章!

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

相关文章阅读

  • 酷狗音乐放歌突然停了,酷狗音乐放着放着就不放了
  • 如何将歌曲下载到u盘,酷狗音乐下载歌曲到u盘步骤
  • 酷狗音乐分享到朋友圈,分享酷狗音乐到朋友圈
  • 酷狗音乐运行中出了点问题反馈一下啰,如何解决酷狗音乐
  • 酷狗音乐下载的vip歌曲到期后怎么听,酷狗音乐vip到期后下载的歌还有吗
  • 酷狗音乐怎么下载到u盘mp3格式,苹果电脑酷狗音乐怎么下载到u盘
  • 酷狗音乐怎么看一首歌听了多少遍苹果手机,酷狗音乐怎么看一首歌听了多少遍歌
  • 酷狗音乐怎么听歌识曲-,酷狗音乐怎么听歌识曲平板
  • 酷狗音乐的搜索功能,酷狗音乐位置在哪
  • 手机版酷狗音乐的dlna功能在哪里,酷狗的dlna功能在哪
  • 酷狗音乐改性别方法怎么改,酷狗音乐改性别方法在哪里改
  • 酷狗音乐怎么设置桌面显示歌词,手机酷狗音乐怎么在桌面显示歌词
  • 酷狗音乐格式转换mp3格式,酷狗音乐视频转换mp3格式
  • 酷狗音乐年度报告怎么看,酷狗2021年度听歌报告怎么看
  • 酷狗音乐怎么搜索用户昵称,酷狗音乐怎么搜索用户名加好友2020
  • 留言与评论(共有 条评论)
       
    验证码: