Python网络爬虫与信息提取(10)—— 代码搜索全网音乐爬取并下载

前言

今天听歌刷到了汪苏泷,瞬间勾起青春的回忆,然后翻了翻酷狗音乐各种收费,资源还不全,哎…想起了小时候用学习机听歌,偷偷拔了妈妈手机里的micro卡下载qq音乐的歌曲然后导入学习机,没有歌词又听不清唱的啥抄的一堆拼音版本的歌词哈哈哈哈。长大了就要学会解决问题了,学了爬虫就是用来干活的!
完整代码在文末,仅供学习使用请勿用作商业用途!转载声明原文地址,如有侵权联系删除谢谢~

目标

定义一个变量存要搜的歌名,运行程序就可以直接下载到本地。

爬取网站

这里安利一个音乐网站:音乐网

特点:界面简介音乐非常全
还算良心吧(对程序员来说),可以两次免费下载,之后几块钱六个月下载权限。为什么对程序员良心呢,因为它虽然下载两次之后收费,但是我查了网页源码,它在播放歌曲的时候歌曲的url是直接插在audio标签的src下的,然后播放歌曲是不限次数的,哈哈哈哈不想说啥了,可能他们的前端小哥哥比较友好吧。

代码设计

代码框架

搜索歌曲设计到了网页按钮的点击,所以本代码采用requests库加selenium库加Xpath解析html的技术路线。
requests库:

这就不多说了,用于模拟网页请求的库,非常强大,这里我主要用来下载mp3文件

selenium库:

也非常强大,可以模拟打开网页,点击按钮,提交表单等等这里我主要用来模拟登陆网站点击按钮

Xpath:

爬虫选手应该都知道吧,这是网页解析的帮手,常用的还有re库,beautiful soup库,我用了感觉还是xpath好用,配置谷歌浏览器的xpath helper插件简直无敌,解析网页直接无脑化。

代码原理

大致流程如下:

  • 登陆网站
  • 搜索歌曲
  • 获取歌曲的url
  • 下载url对应的歌曲

准备

这里我使用的是谷歌浏览器,打开浏览器需要安装chrome driver,下载地址如下:chrome driver下载地址
确定自己谷歌浏览器的版本可以在地址框输入:

chrome://version

在这里插入图片描述

下载对应的版本完成后解压得到chrome_driver.exe文件,放到你的py脚本同样的目录下即可。

登陆网站

这里使用的是selenium中的webdriver,核心代码如下:

from selenium import webdriver

    opt = webdriver.ChromeOptions()  # 创建浏览器
    #opt.add_argument('--headless')                #无窗口模式
    opt.add_argument("--mute-audio")  # 静音
    driver = webdriver.Chrome(options=opt)  # 创建浏览器对象

    print("打开网页")
    driver.get('http://www.gequdaquan.net/gqss/index.html')  # 打开网页

这段代码很简单,首先创建浏览器对象,然后启动静音模式因为我们目标是下载,点击播放才有歌曲地址到时候没有浏览器就开始唱歌实在鬼畜,你还关不掉哈哈哈。接着调用get函数打开网页。

搜索歌曲

打开xpath插件,按住shift + 鼠标左键点击某处就会自动获得xpath路径:
Python网络爬虫与信息提取(10)—— 代码搜索全网音乐爬取并下载_第1张图片
这里要考虑一个问题,webdriver加载网页会十分的慢…不知道具体原因是什么大概率是chrome_driver.exe的问题,因此我们不能在html没加载完成就解析网页,这样会抛出两种类型的异常

  • xpath路径解析错误
  • 解析了空的xpath没有获得按钮对象然后调用按钮的点击函数抛出异常

那就有了思路,让一段有几率抛出异常的代码一直执行直到不抛出异常,实现很简单:

def getXpath(driver,path):
    flag = True
    while flag is True:
        try:
            flag = False
            driver.find_element_by_xpath(path)
        except:
            flag = True

    return driver.find_element_by_xpath(path)

定义标志位True默认让循环一直进行,执行会异常的句子时修改标志位为False,如果发生了异常将标志位改回True,否则就直接退出了死循环。
异常解决了之后处理搜索问题,那就是获取按钮控件将搜索文本放到搜索框点击搜索按钮即可:

	print("打开搜素框")
    driver.find_element_by_xpath("//span[@data-action = \"search\"]").click()  # 点击按钮

    print("搜索音乐")
    getXpath(driver, "//div[@class='search-group']/input[@id='search-wd']").send_keys(search_name)
    getXpath(driver, "//div[@class='search-group']/button[@class='search-submit']").submit()

获取歌曲url

之前分析了网页,音乐是可以免费无限次播放的,并且播放后会获得歌曲的下载地址,因此我们只需要点击搜索完歌曲后点击播放按钮,然后获得歌曲地址的文本即可,这里同样要考虑一个问题:搜索歌曲会重新加载网页,如果没加载完我们就操作会产生上述的两种异常。因此我们需要对搜索网页后点击播放按钮这一操作加上上文类似的异常处理代码:

    print("播放音乐")
    # 因为搜索会重新加载界面,如果获取不到按钮控件则不能调用点击函数会抛出异常
    flag = True
    while flag is True:
        try:
            flag = False
            getXpath(driver, "//a[@class='player-btn btn-play']").click()
        except:
            flag =True

接下来就是获取歌曲下载地址:

    print("获取地址")
    #music_url = str(driver.find_element_by_xpath("//audio").get_attribute("src"))
    music_url = str(getXpath(driver, "//audio").get_attribute("src"))
    print(music_url)

获取完成后关闭音乐播放推出浏览器:

    print("关闭音乐")
    getXpath(driver, "//a[@class='player-btn btn-play btn-state-paused']").click()

    driver.quit()

下载歌曲

python爬虫下载网页流文件都是可以用统一格式,都写了大部分注释,原理简单不做累述,代码如下:

def DownloadFile(mp3_url, save_url,file_name):
    try:
        if mp3_url is None or save_url is None or file_name is None:
            print('参数错误')
            return None
        # 文件夹不存在,则创建文件夹
        folder = os.path.exists(save_url)
        if not folder:
            os.makedirs(save_url)
        # 读取MP3资源
        res = requests.get(mp3_url,stream=True)
        # 获取文件地址
        file_path = os.path.join(save_url, file_name)
        print('开始写入文件:', file_path)
        # 打开本地文件夹路径file_path,以二进制流方式写入,保存到本地
        with open(file_path, 'wb') as fd:
            for chunk in res.iter_content():
                fd.write(chunk)
        print(file_name+' 成功下载!')
    except:
        print("程序错误")

运行测试

Python网络爬虫与信息提取(10)—— 代码搜索全网音乐爬取并下载_第2张图片
下了首万有引力。

问题

这种方法确实是可行的,并且稍微修改就可以在这个网页上批量下载歌曲,但是webdriver响应网站属实太慢了,找不到解决办法,而且如果设置无窗口登陆网站会更更更慢,我真是郁闷了。

完整代码

# coding=utf-8

from selenium import webdriver

import requests

import os


def DownloadFile(mp3_url, save_url,file_name):
    try:
        if mp3_url is None or save_url is None or file_name is None:
            print('参数错误')
            return None
        # 文件夹不存在,则创建文件夹
        folder = os.path.exists(save_url)
        if not folder:
            os.makedirs(save_url)
        # 读取MP3资源
        res = requests.get(mp3_url,stream=True)
        # 获取文件地址
        file_path = os.path.join(save_url, file_name)
        print('开始写入文件:', file_path)
        # 打开本地文件夹路径file_path,以二进制流方式写入,保存到本地
        with open(file_path, 'wb') as fd:
            for chunk in res.iter_content():
                fd.write(chunk)
        print(file_name+' 成功下载!')
    except:
        print("程序错误")


def getMusicUrl(search_name):
    opt = webdriver.ChromeOptions()  # 创建浏览器
    #opt.add_argument('--headless')                #无窗口模式
    opt.add_argument("--mute-audio")  # 静音
    driver = webdriver.Chrome(options=opt)  # 创建浏览器对象

    print("打开网页")
    driver.get('http://www.gequdaquan.net/gqss/index.html')  # 打开网页

    print("打开搜素框")
    driver.find_element_by_xpath("//span[@data-action = \"search\"]").click()  # 点击按钮

    print("搜索音乐")
    getXpath(driver, "//div[@class='search-group']/input[@id='search-wd']").send_keys(search_name)
    getXpath(driver, "//div[@class='search-group']/button[@class='search-submit']").submit()

    print("播放音乐")
    # 因为搜索会重新加载界面,如果获取不到按钮控件则不能调用点击函数会抛出异常
    flag = True
    while flag is True:
        try:
            flag = False
            getXpath(driver, "//a[@class='player-btn btn-play']").click()
        except:
            flag =True

    print("获取地址")
    #music_url = str(driver.find_element_by_xpath("//audio").get_attribute("src"))
    music_url = str(getXpath(driver, "//audio").get_attribute("src"))
    print(music_url)


    print("关闭音乐")
    getXpath(driver, "//a[@class='player-btn btn-play btn-state-paused']").click()

    driver.quit()
    return music_url

def getXpath(driver,path):
    flag = True
    while flag is True:
        try:
            flag = False
            driver.find_element_by_xpath(path)
        except:
            flag = True

    return driver.find_element_by_xpath(path)



if __name__ == '__main__':
    search_name = "万有引力"
    savaer_path = "D://music//"

    print("开始获取url")
    music_url = getMusicUrl(search_name)
    print("开始下载")
    DownloadFile(music_url, savaer_path, search_name + ".mp3")

你可能感兴趣的:(爬虫)