浅色圆锥曲线爱好者PostsNotesAbout

selenium自动收藏网易云曲目

selenium 初使用。

**版本信息** | Python | 3.6.0 | | :----------------: | :----------: | | Selenium | 3.4.3 | | Chromedriver_mac64 | 2.33 | | Chrome | 62.0.3202.94 |

废话部分

很久以来自己的朋友群中经常会分享网易云音乐的歌曲……然而对其整理并不是很轻松,自从有了Faya之后自动存取链接部分是简单实现了。

0

关于歌曲页面可以参考这里,存储部分代码大概这样:

python
def save(msg):
url_reg = re.compile(r'(http://music.163.com[^\s]*)')
wyyurl = re.findall(url_reg, msg)[0].replace('/#','')
if not wyyurl:
return
headers = {
'Host': 'music.163.com',
'Referer': 'http://music.163.com/',
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36'
}
tit_re = re.compile('<title>(.+)</title>')
songinfo = re.findall(tit_re, requests.get(wyyurl , headers = headers).text)
songinfo = songinfo[0].replace(' - 网易云音乐', '')
with open('songinfo.txt', 'a+', encoding='utf-8') as lt:
lt.write(','+songinfo)
with open('songurl.txt', 'a+', encoding='utf-8') as songurl:
songurl.write(','+wyyurl)

1

因为是之后按照时间顺序读取,图省事就直接写进了 txt,其实这样不是很好。非常 ugly

但是就算这样还是需要定时进行手工收藏,所以一直以一种类似于 osascript 的方法进行更新,代码如下:

python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import os
with open ('songurl.txt' ,'r') as l:
songs = l.read().split(',')
for song in songs:
print(song)
os.system("open -a \"Google Chrome\" %s"%song)
input() #用于暂停打开
(当然仅限 mac 使用)

这样的好处是可以再看一遍所有链接指向的歌曲,看看最近都分享了啥。但是不及时,经常过很久才会想起来更新一次,因为 Faya 现在运行在 RaspberryPi 上,从上面同步文件也有点小烦琐。其实就是懒

正题

那么就是 selenium 的正式使用了(~ ̄ △  ̄)~ python 和 chrome 的安装并不多说,这里额外需求的是pip3 install selenium,以及去 https://sites.google.com/a/chromium.org/chromedriver/安装 chromedriver。

之后可以使用以下简单的代码测试自己是否正确配置了环境。

python
#!/user/bin/env python
# -*-coding:utf-8-*-
from selenium import webdriver
import time
options = webdriver.ChromeOptions()
options.add_argument('lang=zh_CN.UTF-8')
options.add_argument('user-agent="Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36"')
driver = webdriver.Chrome(chrome_options=options)
driver.get("https://www.google.com")
driver.find_element_by_name('q').send_keys('selenium')
driver.find_element_by_name('btnK').click()
time.sleep(20) #20秒后关闭
driver.close()

如果正常就可以看到如下 python 打开了一个浏览器,输入了selenium然后点击了搜索。

2

我们的目标当然是http://music.163.com

3

要收藏第一步当然是要登录。

因为不记得密码,这里选择的方案是使用第三方(qq)登陆后存取 cookies 用来下次登录。

前半部分和之前一样,代码如下:

python
from selenium import webdriver
options = webdriver.ChromeOptions()
options.add_argument('lang=zh_CN.UTF-8')
options.add_argument('user-agent="Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36"')
driver = webdriver.Chrome(chrome_options=options)
driver.get("http://music.163.com")
input() #在这时手动登录,登陆完成后按任意键继续
cookies = driver.get_cookies() #获取当前cookies
print(cookies)
with open('xxx.xx')…… #这里可以以任意自己喜欢的方式储存当前的cookies

同样因为图省事,在这里选择直接复制print(cookies)的结果写入 script 中。

其中cookies的结果大致是:

c = [{'domain': '.music.163.com',......'}, {'domain': '.music.163.com',......'}, {'domain': '.music.163.com',......'}, {'domain': '.music.163.com',......'}, {'domain': '.music.163.com',......'}]

这样list的格式,因而要

python
for each in cookies:
driver.add_cookie(each)

要注意在使用 selenium 的add_cookie之前需要保证当前页面和cookies是同一个 domain,也就是说第一遍需要不带cookies访问,再添加完之后重新访问一遍。

登录完之后和所有爬虫一样就是分析 html 了,随便打开一首歌的页面,对于收藏按钮右键检查元素:

4

右上选中的部分就是这部分的 html 了。

5

内容为

html
<a
data-res-id="32364761"
data-res-type="18"
data-count="-1"
data-fee="0"
data-payed="0"
data-pl="320000"
data-dl="320000"
data-cp="1"
data-toast="false"
data-st="0"
data-res-action="fav"
class="u-btni u-btni-fav "
href="javascript:;"
>
<i>收藏</i>
</a>

仔细一看这边的内容中<a data-res-id="32364761" >表示这部分的 id 是动态生成的,并不可靠,可没有其他可以简单查找到的其他特征,css 也是复合的,只好选择使用 xpath 了。

6

如果选择得到结果: //*[@id="content-operation"]/a[3]看起来还行。去 selenium 试试看。

得到报错结果如下:

raise exception_class(message, screen, stacktrace) selenium.common.exceptions.NoSuchElementException: Message: no such element: Unable to locate element: {"method":"xpath","selector":"//*[@id="content-operation"]/a[3]"}

看来是没用找到元素,难道是 xpath 错了么?

经过一段时间研究……其实是 iframe 的原因。

再次查看 html,可以看到如下内容:

7

整个页面都在这层 iframe 之下,因而我们要做的就是切换到这个部分再进行搜索。 具体代码:
driver.switch_to.frame('contentFrame')

之后我们再运行上面的搜索也就没有问题了,可以直接使用click()方法模拟点击。

之后正常跳出选择框,检查元素,这边貌似有个xtag的 class 可以直接用来定位,要注意的是xtag后有个空格……理由不是很懂。

8

然而这时候很自信的写了: pop = driver.find_elements_by_class_name('xtag ')

再次得到无法定位的错误

raise exception_class(message, screen, stacktrace) selenium.common.exceptions.NoSuchElementException: Message: no such element: Unable to locate element: {"method":"class_name","selector":"xtag "}

这是为什么呢?明明有那么好用的 class_name,明明也没有多出新的 iframe,可是怎么会变成这样呢?

*两个小时之后*

经过反复的研究分析,最终发现一切的错误只需要等 3 秒种。

如下图所示,窗口的元素是在点击后生成的,在点击X之后移除,因而在点击后直接查询,这时它并没有生成完整,稍微等待一下加载再进行查询就没问题了。

9 因而代码如下:

time.sleep(3) pop = driver.find_elements_by_class_name('xtag ') pop[1].click()

这里还有一个要注意的点,在使用driver.find_element_by_XXXX等方法时,要注意单复数,比如find_element_by_XXXXfind_elements_by_XXXX是不同的,后者返回的是一个 list,也就不能直接使用click()send_keys等方法。

10

终于……我们看到了收藏成功的提示。感动……╮( ̄ ▽  ̄)╭

当然如果这首曲子在歌单中已经有了会返回已存在的提示。

11

完整的工作 pipeline 如下:

python
#!/user/bin/env python
# -*-coding:utf-8-*-
from selenium import webdriver
import time
import os
options = webdriver.ChromeOptions()
options.add_argument('lang=zh_CN.UTF-8')
options.add_argument('user-agent="Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36"')
driver = webdriver.Chrome(chrome_options=options)
#未储存cookies的情况:
driver.get("http://music.163.com")
input() #在这时手动登录,登陆完成后按任意键继续
"""
已储存cookies的情况:
driver.get("http://music.163.com")
cookies = "………" (替换此处)
for each in cookies:
driver.add_cookie(each)
"""
with open ('songurl.txt' ,'r') as l:
songs = l.read().split(',')
#从本地读取歌曲URL
for song in songs:
driver.get(song)
time.sleep(3)
title = driver.title
try:
print('now ' + title)
driver.switch_to.frame('contentFrame')
driver.find_element_by_xpath('//*[@id="content-operation"]/a[3]').click()
print('click ok')
time.sleep(3)
pop = driver.find_elements_by_class_name('xtag ')
pop[1].click() #此处是选择下面一个歌单
print('finished ' + title)
except:
print('skip ' + title)
#遇到错误跳过
time.sleep(2)

下一步就是优化和搬运到 RaspberryPi 上了,可以继续参考这篇文章

最后是收集生成的歌单:http://music.163.com/#/m/playlist?id=754282245

♪♪ 有兴趣可以去听听看,都是良曲的说 ♪♪

© 2023