selenium 初使用。
**版本信息** | Python | 3.6.0 | | :----------------: | :----------: | | Selenium | 3.4.3 | | Chromedriver_mac64 | 2.33 | | Chrome | 62.0.3202.94 |
废话部分
很久以来自己的朋友群中经常会分享网易云音乐的歌曲……然而对其整理并不是很轻松,自从有了Faya之后自动存取链接部分是简单实现了。
关于歌曲页面可以参考这里,存储部分代码大概这样:
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:returnheaders = {'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)
但是就算这样还是需要定时进行手工收藏,所以一直以一种类似于 osascript 的方法进行更新,代码如下:
python
#!/usr/bin/env python3# -*- coding: utf-8 -*-import oswith 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() #用于暂停打开
这样的好处是可以再看一遍所有链接指向的歌曲,看看最近都分享了啥。但是不及时,经常过很久才会想起来更新一次,因为 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 webdriverimport timeoptions = 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
然后点击了搜索。
我们的目标当然是http://music.163.com
要收藏第一步当然是要登录。
前半部分和之前一样,代码如下:
python
from selenium import webdriveroptions = 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() #获取当前cookiesprint(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 了,随便打开一首歌的页面,对于收藏按钮右键检查元素:
右上选中的部分就是这部分的 html 了。
内容为
html
<adata-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 了。
如果选择得到结果: //*[@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,可以看到如下内容:
整个页面都在这层 iframe 之下,因而我们要做的就是切换到这个部分再进行搜索。
具体代码:
driver.switch_to.frame('contentFrame')
之后我们再运行上面的搜索也就没有问题了,可以直接使用click()
方法模拟点击。
之后正常跳出选择框,检查元素,这边貌似有个xtag
的 class 可以直接用来定位,要注意的是xtag
后有个空格……理由不是很懂。
然而这时候很自信的写了:
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
之后移除,因而在点击后直接查询,这时它并没有生成完整,稍微等待一下加载再进行查询就没问题了。
因而代码如下:
time.sleep(3) pop = driver.find_elements_by_class_name('xtag ') pop[1].click()
这里还有一个要注意的点,在使用driver.find_element_by_XXXX
等方法时,要注意单复数,比如find_element_by_XXXX
和find_elements_by_XXXX
是不同的,后者返回的是一个 list,也就不能直接使用click()
、send_keys
等方法。
终于……我们看到了收藏成功的提示。感动……╮( ̄ ▽  ̄)╭
当然如果这首曲子在歌单中已经有了会返回已存在的提示。
完整的工作 pipeline 如下:
python
#!/user/bin/env python# -*-coding:utf-8-*-from selenium import webdriverimport timeimport osoptions = 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(',')#从本地读取歌曲URLfor song in songs:driver.get(song)time.sleep(3)title = driver.titletry: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
♪♪ 有兴趣可以去听听看,都是良曲的说 ♪♪