尝试改进与优化。
再上一篇文章中,主要记述了基本使用和查找元素的方法。但是非常难受的是,Chromedriver
现在并不支持 arm 芯片,也没机会使用headless Chromium
,那么就选择PhantomJS
代替吧。
初始化:
python
from selenium.webdriver.common.desired_capabilities import DesiredCapabilitiesdcap = dict(DesiredCapabilities.PHANTOMJS)dcap["phantomjs.page.settings.userAgent"] = ('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"')service_args = ['--load-images=no','--disk-cache=yes','--ignore-ssl-errors=true']driver = webdriver.PhantomJS(desired_capabilities=dcap, service_args=service_args)
其中service_args
分别关闭图片加载,开启缓存,忽略 ssl 错误。也可以写成以下这样,不过编译器不是很推荐。
service_args.append = [] service_args.append('--load-images=no') ##关闭图片加载 service_args.append('--disk-cache=yes') service_args.append('--ignore-ssl-errors=true')
一开始以为这样就好了的我非常天真。。
如上一期所述cookies
为
c = [{'domain': '.music.163.com',......'}, {'domain': '.music.163.com',......'}, {'domain': '.music.163.com',......'}, {'domain': '.music.163.com',......'}, {'domain': '.music.163.com',......'}]
但是却遇到了如下错误:
"errorMessage":"Unable to set Cookie"
经过研究貌似PhantomJS
不支持所有的cookies
种类,有的提出了以下解决办法:
python
driver.delete_all_cookies()for cookie in cookies :driver.add_cookie({k: cookie[k] for k in ('domain', 'name', 'value', 'path', 'expiry') if k in cookie})
但这并没有解决我的问题。
再次查看cookies
本身,惊讶的发现其中'domain': '.music.163.com',......'}
的domain
居然不是每个一样的。。orz
有的是'.music.163.com'
有的是'music.163.com'
就是因为这些最前缺乏.
的内容引起了报错,全部加上就正常了。╮( ̄ ▽  ̄"")╭
上一期的代码中使用了不少time.sleep(5)
这样强制等待的代码,实时上这样并不好,selenium 中也自带了两种等待方式:隐式等待、implicitly_wait
和主动等待WebDriverWait(...).until(...)
使用这样的等待方式也应该能够提高运行速度。
必要的import
:
python
from selenium.webdriver.support.wait import WebDriverWaitfrom selenium.webdriver.support import expected_conditions as ecfrom selenium.webdriver.common.by import By
然后分别等待 iframe、收藏按钮、歌单。分别如下:
python
driver.get(url)driver.implicitly_wait(3)
python
WebDriverWait(driver, 5).until(ec.presence_of_element_located((By.XPATH, '//*[@id="content-operation"]/a[3]')))
python
WebDriverWait(driver,5).until(ec.presence_of_all_elements_located((By.CLASS_NAME, 'xtag ')))
同样也希望能够直接捕获系统通知作为反馈,经检查元素如下:
<div class="auto-1511963709410 m-sysmsg" id="auto-id-lb1drKVAgL3cBugD" style="top: 324px; left: 134.5px;"><div class="sysmsg"><i class="u-icn u-icn-32"></i><span>歌曲已存在!</span></div></div>
因为 class 为sysmsg
就这一处,那么通过 xpath'//div[@class="sysmsg"]/span'
就可以找到了。
python
WebDriverWait(driver, 5, 0.1).until(ec.presence_of_all_elements_located((By.CLASS_NAME, 'sysmsg')))sysmsg = driver.find_element_by_xpath('//div[@class="sysmsg"]/span').text
因为是无页面显示的,如果需要 debug 可以在出错的地方使用截图的方式。
如driver.get_screenshot_as_file('/Users/Cordial/Desktop/1.png')
(下图未关闭图片加载,正确记录了歌单被正常显示)
那么整体如下:
python
#!/user/bin/env python# -*-coding:utf-8-*-import refrom selenium import webdriverimport timefrom selenium.webdriver.common.desired_capabilities import DesiredCapabilitiesfrom selenium.webdriver.support.wait import WebDriverWaitfrom selenium.webdriver.support import expected_conditions as ecfrom selenium.webdriver.common.by import Bydef save(msg):url_reg = re.compile(r'(http://music.163.com[^\s]*)')wyyurl = re.findall(url_reg, msg)if wyyurl:url = wyyurl[0].replace('/#', '')sysmsg = love(url)return sysmsgdef love(url):dcap = dict(DesiredCapabilities.PHANTOMJS)dcap["phantomjs.page.settings.userAgent"] = ('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"')service_args = ['--load-images=no', '--disk-cache=yes', '--ignore-ssl-errors=true']driver = webdriver.PhantomJS(desired_capabilities=dcap, service_args=service_args)driver.get("http://music.163.com/")driver.delete_all_cookies()c = [{'domain': '.music.163.com',......'},{'domain': '.music.163.com',......'},{'domain': '.music.163.com',......'},{'domain': '.music.163.com',......'},{'domain': '.music.163.com',......'}]for each in c:driver.add_cookie(each)driver.get(url)driver.implicitly_wait(3)try:print('now')driver.switch_to.frame('contentFrame')WebDriverWait(driver, 5).until(ec.presence_of_element_located((By.XPATH, '//*[@id="content-operation"]/a[3]')))driver.find_element_by_xpath('//*[@id="content-operation"]/a[3]').click()print('click ok')WebDriverWait(driver, 5).until(ec.presence_of_all_elements_located((By.CLASS_NAME, 'xtag ')))pop = driver.find_elements_by_class_name('xtag ')pop[2].click()WebDriverWait(driver, 5, 0.1).until(ec.presence_of_all_elements_located((By.CLASS_NAME, 'sysmsg')))sysmsg = driver.find_element_by_xpath('//div[@class="sysmsg"]/span').texttime.sleep(2) #不着急关闭title = driver.title.replace(' - 网易云音乐', '').replace(' - 单曲', '')driver.close()print('finished ' + title)return f'{title}:\n{sysmsg}'except Exception as e:title = driver.titlereturn f'收藏{title}失败……,原因:\n{e}'if __name__ == "__main__":print(save_wyy('http://music.163.com/#/m/song?id=22689960'))
这样的形式拿到 RaspberryPi 上也能正常运行了,这样只要有分享就能自动添加到歌单中,还是比较便利的。至于运行时间……貌似不能再快了,担心阻塞多话还是放到 thread 中运行比较好。
如果有多个需要点击的对象,也只需要模拟多按几次就可以了。
再分享一个个人歌单http://music.163.com/#/playlist?id=1995945404
♬♫♪♩ 感谢阅读 ♩♪♫♬