Python爬虫:逆向分析酷我音乐请求参数(支持SQ超品音质)

Posted 夏小悠

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python爬虫:逆向分析酷我音乐请求参数(支持SQ超品音质)相关的知识,希望对你有一定的参考价值。

前言

  免责声明:
    本篇博文的初衷是分享自己学习逆向分析时的个人感悟,所涉及的内容仅供学习、交流,请勿将其用于非法用途!!!任何由此引发的法律纠纷均与作者本人无关,请自行负责!!!
  版权声明:
    未经作者本人授权,禁止转载!!!

在这里插入图片描述
  在我的爬虫专栏中已经对网易云音乐酷狗音乐做了请求参数分析,那本篇博文就分析一下酷我音乐的请求参数,还是老样子,详细代码已上传至我的GitHub
  目标:通过输入歌名或者歌手名,列出相应的音乐信息,然后通过选择某一项,将对应的音乐下载到本地指定目录。
  工具:Google Chrome、PyCharm
  这里就不以我最喜欢的歌手本兮为例,这次咱们搜索目前较活的歌曲----下辈子不一定还能遇见你

在这里插入图片描述

1. 请求分析

  按照惯例,我们先看一下音乐的URL参数,具体操作就不多说了,可以看我的专栏里其他音乐爬虫文章。

在这里插入图片描述

  很轻易地就找到了,音乐链接包含在一个响应体内,JSON格式,通过这个链接就可以下载到相应的音乐。下面来看一下该响应对应的请求:

在这里插入图片描述

  可以清楚地看到,请求方式为GET,下面通过PostMan来查看一下具体参数是什么意思:

在这里插入图片描述

  经分析,必须参数有两个:rid表示歌曲的id,br表示比特率,说通俗点就是音质。那么,重点来了!!!

在这里插入图片描述
  根据经验,这个参数应该是可以改的,毕竟学过语音信号处理。于是乎,尝试了一下:192k320k。卧槽,果然,下载到了稍大的音乐文件:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
  经过和手机端对比,192k表示高品音质,320k表示超品音质。

在这里插入图片描述
在这里插入图片描述

2. 获取参数

  音乐URL参数已经知道是什么意思了,下面来找一下这个参数rid在哪,来到搜索页面:

在这里插入图片描述
  搜索页面还是很nice的,检索结果好多页,不像网易云和酷狗那么扣。下面依旧是行云流水般地查找请求:

在这里插入图片描述
  往下翻,就找到了。

在这里插入图片描述

  像这种搜索结果,直接就出找带search或者key字样的链接,小技巧哦!!!

在这里插入图片描述
  依旧是GET请求,放到PostMan看一下参数:

在这里插入图片描述
  直接就403 Forbidden了,很明显,有反爬虫机制,再去浏览器看一下Request Headers信息:

在这里插入图片描述
  下面在PostMan中加入参数,经测试,请求头需要带上Cookie、csrf、Host、Referer、User-Agent,常规操作。经分析,搜索URL必须的参数key,表示输入的搜索关键字。

在这里插入图片描述

3. 完整代码

  经过上述分析,都OK了,不过在实际的爬取过程中,由于搜索列表那个URL请求时需要重定向,其他的请求URL不需要,所以需要对请求头做一些略微的修改,具体修改方法可参阅代码。

# -*- coding: utf-8 -*-
# @Time    : 2021/5/16 22:41
# @Author  : XiaYouRan
# @Email   : youran.xia@foxmail.com
# @File    : music.py
# @Software: PyCharm


import time
from hashlib import md5
import json
import requests
import re
import os
from urllib import parse


def precess_time(func):
    def wrapper(*args):
        minutes, seconds = divmod(int(args[0]), 60)
        result = str(minutes).zfill(2) + ':' + str(seconds).zfill(2)
        return result

    return wrapper


@precess_time
def get_songtime(time_str):
    return time_str


class KuWoMusic(object):
    def __init__(self):
        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': '_ga=GA1.2.136730414.1610802835; _gid=GA1.2.80092114.1621072767; Hm_lvt_cdb524f'
                                  '42f0ce19b169a8071123a4797=1621072767; Hm_lpvt_cdb524f42f0ce19b169a8071123a4797'
                                  '=1621073279; _gat=1; kw_token=C713RK6IJ8J',
                        'csrf': 'C713RK6IJ8J',
                        'Host': 'www.kuwo.cn',
                        'Referer': ''}

    def get_html(self, url, search_key=None):
        if 'rid' not in url:
            self.headers['Referer'] = 'http://www.kuwo.cn/search/list?key=' + search_key
        else:
            del self.headers['Referer']
            del self.headers['csrf']
        try:
            response = requests.get(url, headers=self.headers, verify=False)
            response.raise_for_status()
            response.encoding = 'utf-8'
            return response.text
        except Exception as err:
            print(err)
            return '请求异常'

    def parse_text(self, text):
        print('{:*^80}'.format('搜索结果如下'))
        print('{0:{5}<5}{1:{5}<15}{2:{5}<10}{3:{5}<10}{4:{5}<20}'.format('序号', '歌名', '歌手', '时长(s)', '专辑', chr(12288)))
        print('{:-^84}'.format('-'))
        song_list = json.loads(text)['data']['list']
        count = 0
        info_list = []
        for song in song_list:
            singer_name = song['artist']
            song_name = song['name']
            album_name = song['album']
            rid = song['rid']
            time_str = get_songtime(song['duration'])
            info_list.append([rid, song_name, singer_name])
            print('{0:{5}<5}{1:{5}<20}{2:{5}<10}{3:{5}<10}{4:{5}<20}'.format(count, song_name, singer_name, time_str, album_name, chr(12288)))
            count += 1
            if count == 10:
                break
        print('{:*^80}'.format('*'))
        return info_list

    def save_file(self, song_text, download_info):
        filepath = './download'
        if not os.path.exists(filepath):
            os.mkdir(filepath)
        song_url = json.loads(song_text)['url']
        del self.headers['Host']
        response = requests.get(song_url, headers=self.headers)
        audio_name = download_info[2] + ' - ' + download_info[1]
        with open(os.path.join(filepath, audio_name) + '.mp3', 'wb') as f:
            f.write(response.content)
            print("下载完毕!")


def kw_main():
    kw = KuWoMusic()
    search_info = input("请输入歌名或歌手: ")
    search_key = parse.quote(search_info)
    # pn表示页数, 默认一页30条歌曲信息
    search_url = 'http://www.kuwo.cn/api/www/search/searchMusicBykeyWord?key={}&pn=1&rn=30'.format(search_key)
    search_text = kw.get_html(search_url, search_key)
    info_list = kw.parse_text(search_text)

    while True:
        input_index = eval(input("请输入要下载歌曲的序号(-1退出): "))
        if input_index == -1:
            break
        download_info = info_list[input_index]
        # 流畅音质  128k
        # 高频音质  192k
        # 超品音质  320k
        song_info_url = 'http://www.kuwo.cn/url?rid={0}&type=convert_url3&br=128kmp3'.format(download_info[0])
        song_text = kw.get_html(song_info_url)
        kw.save_file(song_text, download_info)


if __name__ == '__main__':
    kw_main()

  运行结果以及完整代码已经上传到我的GitHub,欢迎Fork哦!

结束语

  没想到,酷我音乐能直接修改参数就可以下载到超品音乐,啧啧啧,有点离谱哦,哈哈哈哈哈哈!!!

Musicer开源代码仓库


  Musicer音乐爬虫已经开源了哦,持续更新中,欢迎来踩来Star哦!ヾ(≧∇≦*)ヾ
  如果对Python爬虫感兴趣的话,欢迎关注我的爬虫专栏,有问题及时联系哦!

以上是关于Python爬虫:逆向分析酷我音乐请求参数(支持SQ超品音质)的主要内容,如果未能解决你的问题,请参考以下文章

Python爬虫 | 爬取酷我音乐并下载——requests库之GET方法(免费听歌!!!)

Python爬虫从0到1 | 爬取酷我音乐信息并下载 ——requests库之GET方法(能省钱!!!)

JS 逆向百例拉勾网爬虫,traceparent__lg_stoken__X-S-HEADER 等参数分析

我去!爬虫遇到JS逆向AES加密反爬,哭了

python简单爬虫

Python爬虫:通过js逆向我发现了斗鱼视频请求参数的加密原理