利用 Python 编写一个 VIP 音乐下载脚本

在这篇博客中,我们将介绍如何使用 Python 编写一个简单的 VIP 音乐下载脚本,利用网页爬虫技术从一个音乐网站下载歌曲。通过解析网页,获取歌曲的真实下载链接,并将音乐文件保存到本地。我们将使用 requestsBeautifulSoup 库来实现这个过程。

目标

本脚本的主要功能是:

  1. 根据用户输入的歌手名或歌曲名,获取与其相关的音乐链接。
  2. 提取音乐的下载链接(通过解析动态加载的内容)。
  3. 下载音乐文件并保存到本地。

环境准备

在开始之前,确保你已经安装了以下 Python 库:

  • requests:用于发送 HTTP 请求。
  • beautifulsoup4:用于解析 HTML 内容。
  • re:用于处理正则表达式,提取网页中动态加载的内容。

你可以通过以下命令来安装所需的库:

pip install requests beautifulsoup4

步骤 1:初始化请求头和 Cookies

许多网站会根据请求头(Headers)和 Cookies 来验证访问者的身份,因此我们需要手动设置这些信息。通常,网络爬虫访问的请求头会模仿真实用户浏览器的请求,避免被网站屏蔽。

headers = {
    "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.7",
    "Accept-Language": "zh-CN,zh;q=0.9",
    "Cache-Control": "max-age=0",
    "Connection": "keep-alive",
    "Sec-Fetch-Dest": "document",
    "Sec-Fetch-Mode": "navigate",
    "Sec-Fetch-Site": "none",
    "Sec-Fetch-User": "?1",
    "Upgrade-Insecure-Requests": "1",
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36"
}

cookies = {
    "Hm_lvt_c2b69091f94cb4368f25c28fc7c2d28c": "1729832766",
    "HMACCOUNT": "A5E96BCC045D9E68",
    "Hm_lpvt_c2b69091f94cb4368f25c28fc7c2d28c": "1729843476"
}

步骤 2:定义文件名清理函数

为了避免文件名中包含非法字符(如 <>:"/\|?*\n 等),我们需要编写一个函数来清理文件名。这个函数会将不允许的字符替换为空字符或其他安全字符。

def sanitize_filename(title):
    # 去除换行符和其他不适合的字符
    sanitized_title = re.sub(r'[<>:"/\\|?*\n]', '', title)
    return sanitized_title

步骤 3:获取歌曲的下载链接

我们首先要获取与用户输入的歌曲相关的页面链接。这可以通过搜索功能实现。在获取到页面后,我们使用 BeautifulSoup 解析页面的 HTML 内容,查找所有包含音乐链接的 <a> 标签。

def search_music(name):
    url = f"https://www.gequbao.com/s/{name}"
    response = requests.get(url, headers=headers, cookies=cookies)
    bs4 = BeautifulSoup(response.text, 'html.parser')
    links = bs4.find_all('a', attrs={'class': 'music-link'})
    
    hrefs = []
    for link in links:
        href = link.get('href')  # 获取 href 属性值
        span = link.find('span')  # 查找内部的 <span> 标签
        if span:
            title = span.text  # 获取歌曲标题
            hrefs.append(('https://www.gequbao.com/' + href, title))
    
    return hrefs

步骤 4:提取实际的音频下载链接

从上一步获取到的歌曲链接,我们需要进一步解析每个歌曲详情页面。通过分析页面中的 JavaScript,我们能够提取出动态加载的音频播放链接。我们通过正则表达式来匹配并提取这些信息。

def get_music_url(href):
    response = requests.get(href, headers=headers, cookies=cookies)
    
    # 通过正则表达式获取动态生成的 play_id 和 mp3_id
    play_id_match = re.search(r"window\.play_id\s*=\s*['\"]([^'\"]+)['\"]", response.text)
    mp3_id_match = re.search(r"window\.mp3_id\s*=\s*['\"]([^'\"]+)['\"]", response.text)
    
    if play_id_match and mp3_id_match:
        play_id = play_id_match.group(1)
        mp3_id = mp3_id_match.group(1)

        # 请求实际的音乐文件下载链接
        url = "https://www.gequbao.com/api/play-url"
        data = {"id": play_id}
        response = requests.post(url, headers=headers, cookies=cookies, data=data)
        
        if response.status_code == 200:
            music_url = response.json()['data']['url']
            return music_url
    return None

步骤 5:下载歌曲并保存到本地

获取到实际的音乐下载链接后,我们就可以将音乐文件保存到本地了。为了保证文件路径的正确性,我们会使用 sanitize_filename 函数来清理文件名,避免文件系统错误。

def download_music(music_url, title, directory):
    response = requests.get(music_url, headers=headers, cookies=cookies)
    if response.status_code == 200:
        filename = f"{sanitize_filename(title)}.mp3"
        file_path = os.path.join(directory, filename)

        # 确保目标文件夹存在
        os.makedirs(directory, exist_ok=True)

        # 保存文件
        with open(file_path, "wb") as file:
            file.write(response.content)
        print(f"下载完成: {title}")
    else:
        print(f"下载失败: {title}")

步骤 6:用户交互与批量下载

为了让用户更方便地使用该脚本,我们加入了用户交互功能,允许用户输入歌手名或歌曲名,并选择是否批量下载搜索结果中的所有歌曲,或者选择下载指定数量的歌曲。

def main():
    name = input("请输入歌手名或歌曲名: ")
    hrefs = search_music(name)
    
    print(f"找到 {len(hrefs)} 首匹配的歌曲:")
    for i, (href, title) in enumerate(hrefs, start=1):
        print(f"{i}. {title}")
    
    operation = input("是否下载所有歌曲?(y/n) 或输入想要下载的歌曲数量: ")
    if operation.lower() == 'y':
        for href, title in hrefs:
            music_url = get_music_url(href)
            if music_url:
                download_music(music_url, title, name)
    else:
        try:
            num = int(operation)
            for href, title in hrefs[:num]:
                music_url = get_music_url(href)
                if music_url:
                    download_music(music_url, title, name)
        except ValueError:
            print("请输入有效的数字或选择 'y' 下载所有歌曲。")

完整代码

import os

import requests
import re
from bs4 import BeautifulSoup

def sanitize_filename(title):
    # 去除换行符和其他不适合的字符
    sanitized_title = re.sub(r'[<>:"/\\|?*\n]', '', title)
    return sanitized_title

def music_load(headers, cookies, title):
    response = requests.get(href, headers=headers, cookies=cookies)
    match = re.search(r"window\.play_id\s*=\s*['\"]([^'\"]+)['\"]", response.text)
    play_id = match.group(1)
    match = re.search(r"window\.mp3_id\s*=\s*['\"]([^'\"]+)['\"]", response.text)
    mp3_id = match.group(1)
    headers = {
        "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.7",
        "Accept-Language": "zh-CN,zh;q=0.9",
        "Cache-Control": "max-age=0",
        "Connection": "keep-alive",
        "Referer": "https://www.gequbao.com/s/%E5%BC%A0%E6%9D%B0",
        "Sec-Fetch-Dest": "document",
        "Sec-Fetch-Mode": "navigate",
        "Sec-Fetch-Site": "same-origin",
        "Sec-Fetch-User": "?1",
        "Upgrade-Insecure-Requests": "1",
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36",
        "sec-ch-ua": "\"Google Chrome\";v=\"129\", \"Not=A?Brand\";v=\"8\", \"Chromium\";v=\"129\"",
        "sec-ch-ua-mobile": "?0",
        "sec-ch-ua-platform": "\"Windows\""
    }
    cookies = {
        "Hm_lvt_c2b69091f94cb4368f25c28fc7c2d28c": "1729832766",
        "HMACCOUNT": "A5E96BCC045D9E68",
        "Hm_lpvt_c2b69091f94cb4368f25c28fc7c2d28c": "1729844345"
    }

    url = "https://www.gequbao.com/api/play-url"
    data = {
        "id": play_id
    }
    response = requests.post(url, headers=headers, cookies=cookies, data=data)
    music_url = response.json()['data']['url']
    cleaned_title = sanitize_filename(title)

    response = requests.get(music_url, headers=headers, cookies=cookies)
    directory = f'{name}'
    filename = f"{cleaned_title}-{name}.mp3"
    # 确保目录存在
    os.makedirs(directory, exist_ok=True)

    # 使用 with open 创建文件
    file_path = os.path.join(directory, filename)
    print(f'文件已创建: {file_path}')
    print(f"正在下载 {cleaned_title}-{name} 歌曲...")
    with open(file_path, "wb") as file:
        file.write(response.content)
    print(f"{cleaned_title}-{name} 歌曲下载完成!")

headers = {
    "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.7",
    "Accept-Language": "zh-CN,zh;q=0.9",
    "Cache-Control": "max-age=0",
    "Connection": "keep-alive",
    "Sec-Fetch-Dest": "document",
    "Sec-Fetch-Mode": "navigate",
    "Sec-Fetch-Site": "none",
    "Sec-Fetch-User": "?1",
    "Upgrade-Insecure-Requests": "1",
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36",
    "^sec-ch-ua": "^\\^Google",
    "sec-ch-ua-mobile": "?0",
    "^sec-ch-ua-platform": "^\\^Windows^^^"
}
cookies = {
    "Hm_lvt_c2b69091f94cb4368f25c28fc7c2d28c": "1729832766",
    "HMACCOUNT": "A5E96BCC045D9E68",
    "Hm_lpvt_c2b69091f94cb4368f25c28fc7c2d28c": "1729843476"
}
name = input("请输入歌手名或者歌曲名:")
url = f"https://www.gequbao.com/s/{name}"
response = requests.get(url, headers=headers, cookies=cookies)
bs4 = BeautifulSoup(response.text, 'html.parser')
links = bs4.find_all('a', attrs={'class': 'music-link'})
hrefs = []
# 遍历标签并获取属性值
for link in links:
    href = link.get('href')  # 获取 href 属性值
    span = link.find('span')  # 查找内部的 <span> 标签
    if span:
        title = span.text  # 打印 <span> 标签的文本内容  # 获取 title 属性值
        hrefs.append(('https://www.gequbao.com/' + href, title))
operation = input("全部下载?(y/n)or 歌曲数量")
if operation.lower() == 'y':
    for href, title in hrefs:
        music_load(headers=headers, cookies=cookies, title=title)
elif operation.isdigit():
    for href, title in hrefs[:int(operation)]:
        music_load(headers=headers, cookies=cookies, title=title)
else:
    want_music = input("请输入你想下载的歌曲(歌名之间用空格隔开):")
    titles = want_music.split(' ')
    for user_title in titles:
        for href, title in hrefs:
            if user_title in title:
                music_load(headers=headers, cookies=cookies, title=user_title)
                break

总结

在这篇文章中,我们介绍了如何利用 Python 编写一个简单的 VIP 音乐下载脚本。通过以下几个步骤,我们成功实现了从一个音乐网站获取歌曲下载链接并保存音乐文件的功能:

  1. 环境准备:使用 requests 和 beautifulsoup4 库,构建请求并解析网页内容。
  2. 请求头与 Cookies:设置请求头和 Cookies,以模拟真实用户浏览器的行为,避免被网站屏蔽。
  3. 文件名清理:编写函数去除非法字符,确保下载的文件名有效且不引发系统错误。
  4. 获取歌曲链接与下载:通过解析音乐页面,提取音乐的实际下载链接,并将音乐文件下载并保存在本地。
  5. 用户交互:通过命令行与用户互动,支持按歌手名或歌曲名搜索,提供批量下载的功能。

通过这段代码,你可以轻松下载你喜欢的音乐,无论是单曲还是一系列歌曲。此脚本在实际应用中非常实用,尤其是对于喜欢收集音乐的朋友。

可能的改进

  • 错误处理:目前的脚本在网络请求失败或文件下载失败时仅简单输出错误信息。未来可以加入更多的错误处理机制(如重试、日志记录等)。
  • 支持更多音乐平台:目前脚本仅针对一个音乐网站进行爬取,未来可以扩展到支持更多的平台,增加更多的功能,如音质选择、自动分类等。
  • 优化用户界面:如果要让更多用户使用该脚本,可以考虑开发图形化界面(GUI)或提供命令行参数支持,增加操作的便捷性。

评论区讨论与留言

我们非常欢迎大家在评论区分享你的看法、建议或遇到的问题。以下是一些可以讨论的主题:

  1. 你是否遇到过类似的爬虫问题?如何解决的?
  2. 是否有更好的方法来提高脚本的下载效率或准确性?
  3. 有没有其他音乐平台的 API 或爬虫经验可以分享?
  4. 你希望添加哪些功能?例如:音质选择、批量下载等。

留言与讨论不仅可以帮助我们改进脚本,也能帮助其他读者解决他们可能遇到的问题。如果你在使用过程中遇到任何问题,欢迎随时提问,我们会尽快解答。


感谢大家阅读这篇文章,祝大家在使用脚本时能够愉快地收听到自己喜欢的音乐!

### 关于面包板电源模块 MB102 的 USB 供电规格及兼容性 #### 1. **MB102 基本功能** 面包板电源模块 MB102 是一种常见的实验工具,主要用于为基于面包板的小型电子项目提供稳定的电压输出。它通常具有两路独立的稳压输出:一路为 5V 和另一路可调电压(一般范围为 3V 至 12V)。这种设计使得它可以满足多种芯片和传感器的不同工作电压需求。 #### 2. **USB 供电方式** MB102 支持通过 USB 接口供电,输入电压通常是标准的 5V DC[^1]。由于其内部集成了 LM7805 稳压器以及可调节电位器控制的直流-直流变换电路,因此即使输入来自电脑或其他低功率 USB 设备,也能稳定地向负载供应电力。不过需要注意的是,如果项目的功耗较高,则可能超出某些 USB 端口的最大电流能力(一般是 500mA),从而引起不稳定现象或者保护机制启动断开连接的情况发生。 #### 3. **兼容性分析** 该型号广泛适用于各种微控制器单元 (MCU),特别是那些像 Wemos D1 R32 这样可以通过杜邦线轻松接入并共享相同逻辑级别的系统[^2]。另外,在提到 Arduino Uno 板时也表明了良好的互操作性,因为两者均采用相似的标准接口定义与电气特性参数设置[^4]: - 对于需要 3.3V 工作环境下的组件来说,只需调整好对应跳线帽位置即可实现精准匹配; - 当涉及到更多外围扩展应用场合下,例如带有多重模拟信号采集任务的情形里,利用 MB102 提供干净无干扰的基础能源供给就显得尤为重要了[^3]。 综上所述,对于打算构建以单片机为核心的原型验证平台而言,选用具备良好声誉记录且易于获取配件支持服务链路上下游资源丰富的品牌产品——如这里讨论过的这款特定类型的配电装置不失为明智之举之一。 ```python # 示例 Python 代码展示如何检测硬件状态 import machine pin = machine.Pin(2, machine.Pin.IN) if pin.value() == 1: print("Power supply is stable.") else: print("Check your connections and power source.") ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

木觞清

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值