0


用selenium模拟搜索爬取酷狗试听歌曲及歌词

引入

本人是一个python爱好者,最近刚开始学习selenium库,简单地了解了一下它的特点。

Selenium可以用于模拟真实浏览器对网页的操作,并实时获取网页中的元素,从而绕过一些对ajax请求的分析,直接截取网页内容。

受此启发,我简单写了一个对音乐网站内容进行获取的程序,目的是实现歌曲的搜索以及试听歌曲的快捷下载,以及对应歌词的获取。

接下来是我编写整个程序的过程和逻辑,希望大家可以参考并给出一些建议。

程序实现

一.初始化selenium
from selenium import webdriver

driver = webdriver.Chrome()

初始化selenium的chrome浏览器

二.选择起始网页

这是酷狗的首页的界面:

如果直接从这个界面开始操作,我们需要先获取搜索输入框元素,再用send_keys方法模拟键入歌曲名,还需要找到搜索键的元素并调用click方法跳转搜索界面。

而按照这样的方法跳转后的页面是这样的:

观察页面的URL可以发现其结构相当简单,因此我们选择该URL作为起始,直接用歌曲名构造完整URL:

index_url = 'https://www.kugou.com/yy/html/search.html#searchType=song&searchKeyWord={}'
keyword = input('歌曲搜索:')
driver.get(index_url.format(keyword))
三.获取搜索结果并选择

打开浏览器devtools,观察与搜索内容有关的节点:

不难发现,在一个ul节点下有多个class为clearfix的li节点,每个li节点都代表一条搜索结果,其中包含4个div节点:

第1个div节点下,a节点的title即为“歌手-歌曲名”格式的字符串,并且附有javascript脚本,我们将利用class对其定位,获取歌曲名,并用click方法进入歌曲详情页;

第3个div节点包含了歌曲时长,我们也利用class对其定位;

这里我们直接使用selenium的find_elements方法:

from selenium.webdriver.common.by import By
# 查找歌曲元素
songeles = driver.find_elements(By.CSS_SELECTOR, 'a[class=song_name]')
timeeles = driver.find_elements(By.CSS_SELECTOR, 'div[class=width_t_li]')

接着遍历这两个元素列表,输出搜索到的歌曲信息,并使用input函数实现选择:

# 输出歌曲信息(歌手、曲名、时长)
print('Found {:.0f} songs below---'.format(len(songeles)))
cnt = 0
for songele in songeles:
    cnt += 1
    print('  ', cnt, timeeles[cnt-1].text, songele.text)
# 选择歌曲
song_number = int(input('歌曲序号:'))
四.解析歌曲详情页并下载

获取到选择的歌曲序号后,我们调用click方法点击对应歌曲的li节点,进入详情页:

# 所选歌曲名称
songname = songeles[song_number-1].text
# 进入对应歌曲详情页
songeles[song_number-1].click()
driver.switch_to.window(driver.window_handles[1])

注意这里需要调用switch_to.window方法(如上),切换窗口后才能继续。

之后综合利用CSS选择器和正则表达式,对该页进行解析,获取MP3链接并获取歌词:

# 查找音频节点
audioele = driver.find_element(By.CSS_SELECTOR, 'audio[class=music][id=myAudio]')
# 获取mp3链接
audiourl = audioele.get_attribute('src')

# 获取歌词
songpagesource = driver.page_source
lyrics = re.findall('<p.*?class="ie8FontColor".*?>(.*?)</p>', songpagesource, re.S)
if not lyrics:
    print('No lyric found.')
else:
    while True:
        if lyrics[0] == '\n':
            lyrics.remove('\n')
        else:
            break
    print('{:.0f} pieces of lyrics found.'.format(len(lyrics)))

最后保存歌曲和歌词文件到本地。先定义两个方法:

# 下载歌曲
def save_song_by_url(url, filename):
    response = requests.get(url)
    nowpath = os.getcwd().replace('\\', '/')
    try:
        os.mkdir('song_download')
    except FileExistsError:
        pass
    with open(nowpath + '/song_download/' + filename, 'wb') as f:
        f.write(response.content)

# 下载歌词
def save_lyric(lyrics, filename):
    nowpath = os.getcwd().replace('\\', '/')
    try:
        os.mkdir('lyrics')
    except FileExistsError:
        pass
    with open(nowpath + '/lyrics/' + filename, 'w') as f:
        for lyric in lyrics:
            f.write(lyric)

调用方法并关闭浏览器:

# 下载歌曲、歌词
print('Downloading ', songname, '...')
save_song_by_url(audiourl, songname+'.mp3')
if lyrics:
    save_lyric(lyrics, songname+'.txt')
print('finished.')

driver.close()

运行效果

该方法下载的歌曲均为标准音质,即酷狗的网页版的试听音质。

对于需要付费的歌曲,一般只能下载1分钟的试听片段,歌词一般可以获取。

不需付费的歌曲,一般可以下载全曲。

根据关键词搜索结果如下:(PyCharm内的运行结果)

下载结果:

编写中遇到的一些问题

1.我们这里获取的歌词是从页面里解析出来的,没有lrc字幕文件中的时间轴,而歌词最初来源于一个ajax请求。网页中展示的歌词本身已经经过渲染,这意味着我们还是要从ajax请求中获取原本的歌词文件,如图:

而这个请求中的加密参数signature的构造逻辑我们不清楚。想知道还有没有其它的办法可以绕过这个加密参数,获取歌词源文件内容。

如图是该请求相应中歌词的一部分,包含时间轴信息:

2.selenium的无头模式开启后仍会弹出一个纯白色窗口,任务栏中没有显示,并且无法直接关闭,想知道是怎么回事。

全部代码

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver import ChromeOptions
from time import sleep
import re
import os
import requests

# 下载歌曲
def save_song_by_url(url, filename):
    response = requests.get(url)
    nowpath = os.getcwd().replace('\\', '/')
    try:
        os.mkdir('song_download')
    except FileExistsError:
        pass
    with open(nowpath + '/song_download/' + filename, 'wb') as f:
        f.write(response.content)

# 下载歌词
def save_lyric(lyrics, filename):
    nowpath = os.getcwd().replace('\\', '/')
    try:
        os.mkdir('lyrics')
    except FileExistsError:
        pass
    with open(nowpath + '/lyrics/' + filename, 'w') as f:
        for lyric in lyrics:
            f.write(lyric)

search_url = 'https://www.kugou.com/yy/html/search.html#searchType=song&searchKeyWord={keyword}'
# 输入歌曲名
searchkeyword = input('歌曲名搜索:')
print('Searching...')

# 无头模式
option = ChromeOptions()
option.add_argument('--headless')
# 初始化,打开网页
driver = webdriver.Chrome(options=option)
driver.get(search_url.format(keyword=searchkeyword))

# 查找歌曲元素
songeles = driver.find_elements(By.CSS_SELECTOR, 'a[class=song_name]')
timeeles = driver.find_elements(By.CSS_SELECTOR, 'div[class=width_t_li]')
# 输出歌曲信息(歌手、曲名、时长)
print('Found {:.0f} songs below---'.format(len(songeles)))
cnt = 0
for songele in songeles:
    cnt += 1
    print('  ', cnt, timeeles[cnt-1].text, songele.text)

# 选择歌曲
song_number = int(input('歌曲序号:'))

# 所选歌曲名称
songname = songeles[song_number-1].text
# 进入对应歌曲详情页
songeles[song_number-1].click()
driver.switch_to.window(driver.window_handles[1])

# 查找音频节点
audioele = driver.find_element(By.CSS_SELECTOR, 'audio[class=music][id=myAudio]')
# 获取mp3链接
audiourl = audioele.get_attribute('src')

# 获取歌词
songpagesource = driver.page_source
lyrics = re.findall('<p.*?class="ie8FontColor".*?>(.*?)</p>', songpagesource, re.S)
if not lyrics:
    print('No lyric found.')
else:
    while True:
        if lyrics[0] == '\n':
            lyrics.remove('\n')
        else:
            break
    print('{:.0f} pieces of lyrics found.'.format(len(lyrics)))

# 下载歌曲、歌词
print('Downloading ', songname, '...')
save_song_by_url(audiourl, songname+'.mp3')
if lyrics:
    save_lyric(lyrics, songname+'.txt')
print('finished.')

driver.close()

本文转载自: https://blog.csdn.net/2401_86646747/article/details/141369531
版权归原作者 Togo42d872a1966e8d21 所有, 如有侵权,请联系我们删除。

“用selenium模拟搜索爬取酷狗试听歌曲及歌词”的评论:

还没有评论