做这个小功能的起因是因为最近家里换了新电视,为了能获得最好的观影体验,需要下载许多动辄几十G的4k电影,而让我花钱冲会员或者买蓝光盘自然是不可能的,我就找到了免费的资源网站,需要签到用积分购买电影资源(当然也可以充钱)
可是每天手动签到很麻烦,又可能经常忘,就想自己搞一个脚本自动化签到
我最初的方案是,使用python的selenium库来实现网站模拟点击的操作,使用launchctl定时运行shell脚本执行py文件。但是由于我电脑launchctl功能的未知错误(查遍了google百度也没能找到解决方法)我最终实现的途径是通过sleepwatcher来实现电脑唤醒时自动执行。
方案一
编写plist文件来实现定时任务是当下mac官方最推荐的方法。灵活性也很高,可以任意定时,精确到秒,灵活至单独工作日。相比Linux的crontab有一个优点:当电脑在规定时间在休眠状态的话,在唤醒后依然可以补执行任务,而crontab只会等待下一轮指定运行时间。但是launchctl权限问题可能会导致很多错误,这点使用上可能会有些困扰。
方案二
sleepwatcher可以说使用起来十分简单,但是只能在唤醒时或者休眠时执行任务,使用场景较单一,需要在脚本文件中写额外的代码来避免反复执行任务
下面,我会将两种实现途径都介绍一下
在项目目录里创建code.py
所需导入
from selenium import webdriver
import time
from selenium.webdriver.chrome.options import Options
要使用chrome浏览器,所以需要下载电脑中对应版本的chrome驱动chromedriver文件,版本号可以在chrome的关于中看到。比如我的是87.0.4280.88,在此网址可以下载对应的驱动,下载后将其放在code.py同一路径。
设置浏览器的选项设置,第一行这个很关键,如果不取消掉会在执行的时候蹦出来通知权限的通知框,会使后续的操作失败,值得注意的一点是,headless这个选项在调试阶段最好注释掉,为了方便测试需要看整个自动化的执行流程,当程序没有问题后将整个签到动作隐藏在后台将会十分的优雅,没有任何痕迹得完成签到。
option = Options()
option.add_argument("--disable-infobars") # 取消通知提醒
# option.add_argument("start-maximized")
option.add_argument("--disable-extensions") # 取消扩展
option.add_argument('headless') # 后台运行
# Pass the argument 1 to allow and 2 to block
option.add_experimental_option("prefs", {
"profile.default_content_setting_values.notifications": 2
})
设置提前注册好的账号密码,可以实现多组账号密码依次签到
username = ['[email protected]', '[email protected]']
password = ['xxxx', 'xxxxxx']
这里的find_element_by_xpath是为了指定页面元素并进行填充,点击等操作。
xpath的获得是在chrome里先打开网页,然后F12进入检查,再在想定位的元素上右键检查,选择full xpath,就可以获得对应元素的xpath
获得指定网址的实例化对象,并完成点击等操作。
chrome_driver = '/Users/yao/Documents/PersonalProjects/AutoCheckin/chromedriver' #chromedriver的文件位置
browser = webdriver.Chrome(options=option, executable_path=chrome_driver)
browser.get('https://www.hao4k.cn/qiandao/')
browser.find_element_by_xpath('//*[@id="JD_sign"]').click()
time.sleep(1)
# 输入账号密码 点击登录
browser.find_element_by_xpath('/html/body/div[10]/div/div/div[2]/div[2]/div[6]/div[1]/div/form/div/div[1]/table/tbody/tr/td/input').send_keys(username)
browser.find_element_by_xpath('/html/body/div[10]/div/div/div[2]/div[2]/div[6]/div[1]/div/form/div/div[2]/table/tbody/tr/td/input').send_keys(password)
browser.find_element_by_xpath('/html/body/div[10]/div/div/div[2]/div[2]/div[6]/div[1]/div/form/div/div[5]/label/input').click()
browser.find_element_by_xpath('/html/body/div[10]/div/div/div[2]/div[2]/div[6]/div[1]/div/form/div/div[6]/button').click()
windows = browser.window_handles
browser.switch_to.window(windows[-1])
time.sleep(1)
如果已签到或者有任何错误导致签到失败就会打印FAILED,这步是为了后续输出log.txt中可以看到每次执行的记录
browser.get('https://www.hao4k.cn/qiandao/')
try:
browser.find_element_by_xpath('/html/body/div[9]/div[2]/div[1]/div[1]/a').click()
time.sleep(1)
browser.quit()
print(username+' SUCCEED ', end='')
except:
time.sleep(1)
browser.quit()
print(username + ' FAILED ', end='')
将上述代码封装进autocheckin函数,调用
for u, p in zip(username,password):
autocheckin(u,p)
在同一路径下,创建autocheckin.sh脚本文件
#!/bin/bash
cd /Users/yao/Documents/PersonalProjects/AutoCheckin
lastlog=$(tail -n -1 log.txt)
if ((${lastlog%% *}==$(date "+%Y-%m-%d"))) && ! [[ $lastlog =~ FAILED ]];then
exit 0
else
res=$(/Users/yao/opt/anaconda3/bin/python3 /Users/yao/Documents/PersonalProjects/AutoCheckin/code.py)
time=$(date "+%Y-%m-%d %H:%M:%S")
echo "$time $res" >> /Users/yao/Documents/PersonalProjects/AutoCheckin/log.txt
fi
log.txt中的数据是以这样的形式储存的:
2020-12-30 15:25:51 [email protected] SUCCEED [email protected] SUCCEED
lastlog=$(tail -n -1 log.txt)
读取log.txt中的最后一行数据, 如果记录中的最后一条数据日期是当天且没有FAILED记录就退出脚本程序,反之则执行后续签到程序
=~
符号用于返回是否包含字符串布尔值
在~/Library/LaunchAgents路径下新建plist文件com.yaoMacBook.autocheckin.plist
Label
com.yaoMacBook.autocheckin
ProgramArguments
/Users/yao/Documents/PersonalProjects/AutoCheckin/autocheckin.sh
StartCalendarInterval
Minute
10
Hour
12
RunAtLoad
KeepAlive
WorkingDirectory
/Users/yao/Documents/PersonalProjects/AutoCheckin
Label是全局唯一的标志,是进程名
ProgramArgument是运行的程序和输入参数,如果只有一个就默认运行第一个参数程序
StartCalendarInterval表示在哪天几时几分运行,这里表示每天12点10分运行
RunAtLoad表示是否开启服务时自动运行,默认false
KeepAlive表示是否进程一直在后台运行,默认false
WorkingDirectory表示指定的工作路径
对于脚本文件也需要更改权限,可以执行 chmod +x autocheckin.sh
增加所有用户的执行权限。
然后在~/Library/LaunchAgents路径下启动进程
launchctl load com.yaoMacBook.autocheckin.plist
使用unload停止进程
launchctl unload com.yaoMacBook.autocheckin.plist
start可以单次运行进程来查看是否正确运行
launchctl start com.yaoMacBook.autocheckin.plist
我在我的电脑(MacOS BigSur 11.1)上出现错误,系统日志显示错误代号126,如有朋友知道原因欢迎交流!
第一条路走不通后,我找了另一个方法曲线救国,使用sleepwatcher来实现每次电脑唤醒便执行脚本
具体实现方法参考了这篇文章的sleepwatcher配置部分,
\
> brew install sleepwatcher
> brew services start sleepwatcher
> ps aux | grep sleepwatcher
> cd ~
> touch .sleep
> touch .wakeup
> sudo chmod 777 .sleep
> sudo chmod 777 .wakeup
然后编辑.wakeup
> vim .wakeup
然后就大功告成,可以合盖试一下脚本是否正确执行,log.txt中是否有正确的签到记录