引入
本人是一个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()
版权归原作者 Togo42d872a1966e8d21 所有, 如有侵权,请联系我们删除。