欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

python实现某网站的音乐下载

程序员文章站 2022-04-19 19:37:07
...

写在前面:首先,理论上讲,如果歌曲可以在网页上播放,那么一定有网址(source src)保存着歌曲的源文件。那么利用火狐(或者谷歌)浏览器的F12功能,就可以快速提取出该source src,进而完成歌曲下载了。基于上述操作,我就想到了用python把如前所述封装起来,输入歌曲名称进行选择进而完成下载。

1. 前期准备

  • 开发环境:win10 + py3.5(即windows + py3.x)

  • 需要安装的库:requests 和 selenium(具体安装方法网上有很多,这里不再赘述。其中关于selenium的教程建议参考虫师的《selenium2 python自动化测试》)

  • ps. 这里的某网站指的是QQ音乐,当然酷狗音乐原理相同。网易云会涉及到更加复杂的跳转,由于没有学过前端,暂时无法处理。。。

2. 具体步骤

2.1 网址定位

打开QQ音乐,使用“搜索”按钮进行搜索后(以搜索-崇拜-为例),得到的结果为:

python实现某网站的音乐下载

从图中复制可以得到歌曲搜索网址如下:

https://y.qq.com/portal/search.html#page=1&searchid=1&remoteplace=txt.yqq.top&t=song&w=%E5%B4%87%E6%8B%9C

注意:上述网址中的%E5%B4%87%E6%8B%9C是“崇拜”的HTML可识别编码形式。

接下来我们使用requests.get(url)就可以得到页面内容了,让我们看一下结果:

# coding:utf-8
# 测试返回结果

import requests
import urllib.request

headers = {
        'Host': 'y.qq.com',
        'User-Agent': '', # 这个大家用自己的就好
        'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
        'Accept-Language': 'zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3',
        'Accept-Encoding': 'gzip, deflate, br',
        'Referer': 'http://y.qq.com/',
        'Connection': 'keep-alive',
        'Cache-Control': 'max-age=0',
    }
MusicName = "崇拜"  # 测试用例
urlMusicName = urllib.parse.quote(MusicName)  # 转换成url可以读取的字符串

url = "https://y.qq.com/portal/search.html#page=1&searchid=1&remoteplace=txt.yqq.top&t=song&w=" + urlMusicName
response = requests.get(url, headers = headers)
print(response.text)

运行上述代码,打印结果如下所示:

python实现某网站的音乐下载

由于结果太长,这里我们截取一部分观察。发现结果中出现很多乱码,原来是缺失对response编码的结果。在上述代码中进行修改:

    response = requests.get(url, headers = headers)
    response.encoding = 'utf-8'   # 对结果进行utf-8编码

此时再重新打印,就可以显示中文了!

但是我们会发现,在返回的结果中,并没有显示出歌曲列表,这是为什么呢?

对比一下原网页的F12结果和返回结果我们发现,在原网页中,歌曲列表是存在在这个div里的:

<div class="js_search_tab_cont" id="song_box" style="display: block;">

但是在返回结果中,该div标签的显示为:

<div class="js_search_tab_cont" id="song_box"></div>

内容为空!这也就解释了为什么我们无法得到歌曲列表了,因为根本没有加载出来。

为了进一步解释这个问题,我们需要做以下几件事:

  1. 打开火狐浏览器(因为我selenium用的火狐,所以这里都是使用火狐浏览器,当然使用谷歌也完全没有问题~~),在地址栏中输入about:config,进入浏览器设置页面。

  2. 在页面中输入javascript.enabled,找到后 鼠标右键-切换。

  3. 这样我们就将浏览器的javascript关掉了。

  4. 关掉之后再重新加载原搜索网页,可以发现歌曲列表不见了。

通过上述操作,我们已经弄明白原因,那就是该歌曲列表是通过JavaScript进行加载,而非静态网页,也因此,我们使用静态网页方法进行获取时,是得不到加载后的歌曲列表的。

为了解决上述问题,也查看了不少方法,觉得说的比较全面在这里:传送门-知乎

最后,我选择了一种最不智能的方法,就是—暗中观察。

继续F12,网络–JS–“clint_search”找到了js跳转的真正网址,具体如图:

python实现某网站的音乐下载

这样就完成了请求网址的定位,万里长征走完第一步~

2.2 歌曲列表打印

可能有同学要问了,为什么我们要去定位上述网址呢,上述网址打开之后是什么样子呢?

python实现某网站的音乐下载

乱乱的,像json。为了方便阅读,这里直接使用火狐自带的阅读模式,就是上图中红色框中的button,点击,继续观察:

python实现某网站的音乐下载

注意图中红色框出的部分,“media_mid”,“name”,“title”。后面两个很好解释,那么第一个是做什么用的呢?

在歌曲列表网页中随便点击一首歌曲,可以发现其跳转后的URL为:

https://y.qq.com/n/yqq/song/003JlYgD1SvCYe.html

后面这一长串就是media_mid,原来它是用来定位歌曲的。

具体如何从json中查找出全部有用信息,这就涉及到了python 正则匹配的问题,建议大家自行学习,这里匹配不难,注意细节即可!

将全部有用信息提取出来后,存入字典,并打印在屏幕上,这样就可以自己选择想下载的歌曲了。

python实现某网站的音乐下载

其中,字符串的对齐需要注意一下。因为包含中文和标点符号,因此直接使用`”%-10s”等python自带的对齐方式是不行的,需要重新写对齐函数,我参考了这里中文字符对齐-传送门,并进行了部分修改,得到字符对齐函数如下:

# ================中文检测函数====================
# 参考网址:http://lib.csdn.net/article/python/66507?knId=160
def findChinese(source):
    # text = source.decode('utf8')   # python3 默认为unicode
    r = re.findall('[\u4e00-\u9fa5]', source)
    # 去除空格影响
    condition = lambda t: t != ' '
    results = list(filter(condition, r))
    return results


# ===============填充字符函数======================
# 参考网址:http://lib.csdn.net/article/python/66507?knId=160
# 输入变量说明:
# un_align_str: 输入字符串
# lenh: 半角字符个数;自己设置;默认为0
# lenf: 全角字符个数;自己设置;默认为0
# addh: 半角字符空格
# addf: 全角字符空格
def myAlign(un_align_str, lenh = 0, lenf = 0, addh = ' ', addf = u' '):
    assert isinstance(lenh, int)   # 断言半角长度为整形变量
    assert isinstance(lenf, int)   # 断言全角长度为整形变量
    slen = len(un_align_str)
    # 中文在默认的utf-8编码下显示占用约2个字符
    chn = findChinese(un_align_str)
    numchn = len(chn)
    numspn = slen - numchn
    str = addh * (lenh - numspn) + addf * (lenf - 2 * numchn)
    return str

OK,完成歌曲列表打印!

2.3 链接跳转与歌曲下载

我们发现,当我们点击歌曲的-播放-按钮时,实际上完成的是一次网页跳转(jump~jump~)

python实现某网站的音乐下载

对于这种类似于人的操作,我们可以使用selenium来进行模拟。

具体过程也可以描述成如下步骤:

  1. 定位“播放”按钮

  2. 模拟鼠标左键单击操作

  3. 读取跳转后的网页,查找source src

由于页面加载需要时间,这里我直接使用的是time.sleep()函数来进行等待,另外针对多窗口之间的跳转,selenium也给出了API,那就是driver.window_handles

在这里,需要利用time.sleep()等待句柄加载完成,否则会出现无法读取的情况,因此我用了如下判断语句进行处理

    count = 0
    allhandles = driver.window_handles
    for handle in allhandles:
        count += 1
    if count == 2:
        driver.switch_to_window(driver.window_handles[1])
    else:
        time.sleep(5)
        driver.switch_to_window(driver.window_handles[1])

有了当前driver,我们就可以读取driver.page_source,正则匹配出source src,然后利用requests.get(url).content完成歌曲下载啦!

3. 相关源码

源码已经上传,大家可以自行下载:QQ音乐下载器源码

相关标签: python 音乐