基于对学校打卡页面的简单研究,啊,使用Python和Selenium做了一个打卡程序。加上Windows系统自带的计划任务功能,可以轻松实现每天定时自动打卡。从此再也不用被催被训。
这肯定不用多说了。吧。
浏览器使用火狐的长期支持版本,即Firefox LTS。在官网的“更多语言与下载”页面下拉到底就可以看见。
谷歌浏览器不太好使,更新太多,后续写代码时也有一种怪怪的感觉。但是完全可以实现一样的功能哈。只能说是个人喜好问题选择了火狐长期支持版。
然后下载浏览器驱动。这个驱动是自动控制时要用的。火狐浏览器需要用geckdriver,下载地址在https://github.com/mozilla/geckodriver/releases。谷歌浏览器用chromedriver。
这玩意下载来了之后是要在Windows环境变量里添加参数才能使用的。但是我懒得再加了。由于Python在部署的过程中已经把Python自己的文件夹添加到了环境变量里,所以直接把drive扔进Python根目录里就行了。万岁。
按常规方法装就行,没有什么特别的,也没有什么要改的地方。
pip install selenium
先加上必须用到的time和random基础库。再把Selenium里要用的部分统统import。
import time
import random
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.action_chains import ActionChains
用Python,你的代码可以写得很诡异,但是不可以不规整。记住,在Python里,书写规范是最重要的一环,甚于效率。所以我们定义一个构造方法先。
class Auto_punch:
def __init__(self):
self.option = None
self.options = None
self.driver = None
self.vars = None
没什么特别的用处,就是符合完整的结构书写规范。
先得打开浏览器。这个部分还包括对浏览器进行一些初始设置。
def setup(self):
options = webdriver.FirefoxOptions()
options.set_preference("general.useragent.override",
'-user-agent="Mozilla/5.0 (Linux; U; '
'Android............Gecko) Version/4.0 '
'Chrome/78.0.3904.108 Quark/5.5.5.204 Mobile '
'Safari/537.36"')
options.set_preference("geo.prompt.testing", True)
options.set_preference("geo.prompt.testing.allow", True)
# self.options.add_argument('--disable=gpu')
self.driver = webdriver.Firefox(options=options)
self.driver.implicitly_wait(20)
self.vars = {}
选用火狐浏览器有这一个好:火狐浏览器的设置是一种表单格式。比较直观,也比较详细。
首先是伪装成手机的header。这里把useragent设成了一串相当抽象的字符串。你不理解没关系,浏览器理解就够了。
options.set_preference("general.useragent.override",
'-user-agent="Mozilla/5.0 (Linux; U; '
'Android............Gecko) Version/4.0 '
'Chrome/78.0.3904.108 Quark/5.5.5.204 Mobile '
'Safari/537.36"')
然后是值得注意的两行代码,也算是本环节的关键:
options.set_preference("geo.prompt.testing", True)
options.set_preference("geo.prompt.testing.allow", True)
这两行的作用就是,当浏览器弹出“网页请求获取地理位置数据”窗口时,自动点确定。
打卡网页没有获取到位置数据的话是不准打卡的。既然是数据,那就是可以改的。详见下文…
self.options.add_argument('--disable=gpu')
这个是比较常规的一个选项,不显示窗口,后台自动运行。由于不利于观察运行调试,就注释掉了这行。如果是打算挂在服务器上使用,可以取消注释。
self.driver = webdriver.Firefox(options=options)
self.driver.implicitly_wait(20)
这个是网页加载等待时间。如果需要操作的某个网页元素迟迟没有加载出来,那么它最多会额外等待20秒。这个不影响程序运行速度,所以填大一点也没什么影响。
def quit(self):
self.driver.quit()
def open_url(self):
self.driver.get(
"https://wb.ndky.edu.cn/mobile/index.html?useragent=wxwork&code"
"=zReBN0F8yFPe6RQ2JaevkmPiYCGnTAGb5cnWSsM0k1Q&state=STATE")
self.driver.set_window_size(480, 800)
这两个函数就很直白了,分别负责完成任务后退出浏览器和操控浏览器打开打卡页面并设定浏览器窗口大小。
重头戏。本项目最核心的部分,利用Selenium强大无比的仿真控制功能完成网页定位与打卡。
def Auto_Punch(self):
self.driver.find_element(By.NAME, "username").click()
self.driver.find_element(By.NAME, "username").send_keys("114514")
self.driver.find_element(By.NAME, "password").click()
self.driver.find_element(By.NAME, "password").send_keys("1919810")
self.driver.find_element(By.CSS_SELECTOR, ".weui-btn").click()
self.driver.find_element(By.CSS_SELECTOR, ".hot-service-list .grid-item-wrapper:nth-child(1)").click()
self.driver.execute_script("navigator.geolocation.getCurrentPosition = function(success) { success({coords: {"
"latitude: 30.198982, longitude: 121.298721}}); }")
self.driver.execute_script("arguments[0].click()",self.driver.find_element(By.CSS_SELECTOR, ".weui-cell:nth"
"-child(72) > "
".weui-cell__bd"))
time.sleep(1)
self.driver.find_element(By.CSS_SELECTOR, ".weui-cell:nth-child(72) > .weui-cell__bd").click()
self.driver.find_element(By.CSS_SELECTOR, ".weui-check__label:nth-child(2)").click()
self.driver.find_element(By.CSS_SELECTOR, ".weui-btn").click()
time.sleep(10)
element = self.driver.find_element(By.CSS_SELECTOR, ".weui-btn")
actions = ActionChains(self.driver)
actions.move_to_element(element).perform()
self.driver.find_element(By.CSS_SELECTOR, ".to-lobby").click()
self.driver.find_element(By.CSS_SELECTOR, ".weui-tabbar__item:nth-child(2) > .weui-tabbar__label").click()
self.driver.find_element(By.CSS_SELECTOR, ".weui-btn").click()
element = self.driver.find_element(By.CSS_SELECTOR, ".weui-btn")
actions = ActionChains(self.driver)
actions.move_to_element(element).perform()
self.driver.find_element(By.LINK_TEXT, "确认").click()
self.driver.find_element(By.NAME, "username")
利用名称来匹配元素。这里直接找到用户名输入框,然后通过.click()
和.send_keys()
函数点击输入框并输入用户名。下同。
self.driver.find_element(By.CSS_SELECTOR, ".weui-btn")
利用css的class属性值匹配元素。这是Selenium官方强推的匹配方法,又快又精简。
self.driver.execute_script("navigator.geolocation.getCurrentPosition = function(success) { success({coords: {"
"latitude: 30.198982, longitude: 121.298721}}); }")
这段是之前关于打卡网页定位方式研究的成果。通过Selenium直接给负责定位的Javascript发一个fake callback。效果拔群。这个方法理论上可以解决所有网页定位问题。
time.sleep(1)
负责在无法精确得知等待时间时强制等待一个较长的固定时间。比较常用。据说Selenium老手就很少用这个了。
最后构建main函数。
if __name__ == '__main__':
delay = random.randint(0, 600)
print("本次随机延迟为:" + str(delay))
time.sleep(delay)
print("缓冲结束")
run = Auto_punch()
run.setup()
print("初始化完成")
run.open_url()
print("打开打卡页面")
print("开始自动打卡")
run.Auto_Punch()
print("打卡完成")
print("关闭程序")
run.quit()
为避免后台检测数据异常,这里还使用了一个简单的随机延迟函数,使得每天的自动打卡时间点都不一样,即delay = random.randint(0, 600)
time.sleep(delay)
。
由于windows计划任务配置python脚本的流程过于麻烦,容易出差错,所以我们直接把这个脚本打包成一个exe程序。
pip install pyinstaller
安装打包库。
shift+鼠标右键点击刚写好的python程序的文件夹,在弹出的选项中点击"在此处打开命令行窗口"或者“在此处打开PowerShell窗口”。
pyinstaller -F 自动打卡.py
打包程序。
然后在输出的dist文件夹里就可以看见打包好的exe程序了。
这个太简单了就不写了,随便百度一下再按照自己的需求做修改就行。开摆!
一定要经过复数次的手动测试才可以正式投入使用。血的教训。这个不会出问题的最终版本建立在翻车无数次的基础上…
python+selenium简单易上手,更多资料敬请百度。。。我自动打卡无罪,毕竟我原本就是自动化学生,,,