1 引言
需求 :打卡很容易忘记,想自动化处理此事。
声明 :学习与技术讨论,勿实操!!!
2 思路
思路主要参考:https://github.com/mottled233/buaa_daily_report
在Windows下编写脚本,使用chrome+selenium,模拟浏览器点击;
通过 win10toast 实现在 Win10 系统中发送桌面消息通知;
借助Server酱+PushDeer
推送打卡结果至手机;
最终,使用Windows自带的任务计划程序
实现定时执行脚本。
3 实现
3.1 打卡脚本
daily_report.py :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 import loggingfrom time import sleepimport timeimport datetimeimport requestsfrom selenium import webdriverfrom selenium.webdriver.chrome.options import Optionsfrom selenium.webdriver.common.action_chains import ActionChainsfrom selenium.webdriver.common.by import Byuser = "xxx" passwd = "xxx" position = ("39.97812" , "116.343936" ) SCKEY = "xxx" max_attempt = 5 def log_config () : """ 日志文件配置 """ log_file = "log.log" formatter = logging.Formatter("%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s" ) logger = logging.getLogger("main" ) fh = logging.FileHandler(log_file, mode='w' ) fh.setFormatter(formatter) ch = logging.StreamHandler() ch.setFormatter(formatter) logger.addHandler(fh) logger.addHandler(ch) logger.setLevel(logging.INFO) return logger def sign_in () : """ 模拟签到 """ logger.info("正在进行验证..." ) chrome_options = Options() chrome_options.add_argument('--headless' ) chrome_options.add_argument('--disable-gpu' ) chrome_options.add_argument('--no-sandbox' ) browser = webdriver.Chrome(chrome_options=chrome_options) try : url = "https://app.buaa.edu.cn/uc/wap/login?redirect=https%3A%2F%2Fapp.buaa.edu.cn%2Fsite%2FbuaaStudentNcov%2Findex" browser.get(url) user_name_input = browser.find_element_by_css_selector( '#app > div.content > div:nth-child(1) > input[type=text]' ) user_name_input.send_keys(user) user_pwd_input = browser.find_element_by_css_selector( '#app > div.content > div:nth-child(2) > input[type=password]' ) user_pwd_input.send_keys(passwd) except : logger.info("打开打卡网页失败,请确认网络" ) send_message("北航打卡:打开打卡网页失败,请确认网络" ) exit(0 ) logger.info("成功打开打卡网页" ) login_button = browser.find_element_by_css_selector('#app > div.btn' ) ActionChains(browser).move_to_element(login_button).click(login_button).perform() browser.implicitly_wait(2 ) fail_cnt = 0 while True : location_button = browser.find_elements_by_css_selector( 'body > div.buaaStudentNcov > div.buaaStudentNcov-bg > div > div:nth-child(5) > div > div.warp-list-choose > div.warp-list.two-warp-list.warp-list-margin > div.title-input.title-input-mergin-left' ) if len(location_button) > 0 : logger.info("登录成功" ) break else : if len(browser.find_elements_by_css_selector('div.wapat-btn-box' )) > 0 : send_message("北航打卡:打卡失败,用户名密码错误,程序已退出,请检查" ) logger.info("打卡失败,用户名密码错误,请检查" ) exit(0 ) if fail_cnt >= max_attempt: send_message("北航打卡:登录超时超过最大尝试次数,请检查网络或打卡系统已崩溃" ) logger.info("登录超时超过最大尝试次数" ) exit(0 ) time.sleep(10 ) browser.get("https://app.buaa.edu.cn/site/buaaStudentNcov/index" ) logger.info("登录超时,正在重试" ) fail_cnt += 1 browser.execute_script("window.navigator.geolocation.getCurrentPosition=function(success){" + "var position = {\"coords\" : {\"latitude\": \"" + position[0 ] + "\",\"longitude\": \"" + position[1 ] + "\"}};" + "success(position);}" ) time.sleep(5 ) location_button = browser.find_element(By.XPATH, "/html/body/div[1]/div[1]/div/div[5]/div/div[2]/div[2]/div[2]/input" ) ActionChains(browser).move_to_element(location_button).click(location_button).perform() time.sleep(2 ) location = location_button.get_attribute('value' ) logger.info(f"成功输入经纬度,定位{location} " ) browser.implicitly_wait(3 ) while True : try : submit_button = browser.find_element(By.XPATH, '/html/body/div[1]/div[1]/div/div[6]' ) if submit_button.text.find("您已提交过信息" ) != -1 : result = "打卡失败,您已经提交过" break elif submit_button.text.find("未到填报时间" ) != -1 : result = "未到填报时间" break submit_button.click() result = '提交成功' break except Exception as e: try : reason = browser.find_element_by_css_selector('#wapat > div > div.wapat-title' ).text result = f'打卡失败,原因:{reason} ' break except : time.sleep(1 ) browser.save_screenshot('location_test.png' ) logger.info(result) datee = datetime.date.today() send_message("北航打卡:" + f"{result} {datee} " ) sleep(50 ) browser.quit() logger.info("流程结束" ) def send_message (msg) : """ 发送信息到手机,将结果写入临时文件,便于Windows消息提醒 """ if SCKEY == "" : return payload = {'text' : msg} requests.get(f"https://sc.ftqq.com/{SCKEY} .send" , params=payload) f = open("result.txt" , "w" ) f.write(msg) f.close() if __name__ == "__main__" : logger = log_config() sign_in()
关于位置经纬度获取 :
打开网页版高德地图:https://www.amap.com/
选择指定位置,右键,选择这是哪儿
;
选择更多
里面的分享
;
复制链接,在新的标签页打开,URL会自动补全,其中包含经纬度信息:lng=116.343936&lat=39.97812
关于手机信息推送 :
上面脚本中的变量SCKEY
是填Server酱的Key :
为了手机通知明显,通道配置使用PushDeer,手机安装PushDeer ,配置pushkey:
3.2 Windows消息提醒脚本
buaa_notice.py :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 from winrt.windows.ui.notifications import ToastNotificationManager, ToastNotificationimport winrt.windows.data.xml.dom as domnotifier = ToastNotificationManager.create_toast_notifier(r'xxx' ) title = "北航打卡" f = open("result.txt" , "r" ) desp = f.read() f.close() tString = """<toast duration='short'><audio src = 'ms-winsoundevent:Notification.Reminder' loop = 'false' silent = 'false'/><visual><binding template='ToastText02'><text id="1">""" + title + """</text><text id="2">""" + desp + """</text></binding></visual></toast>""" xDoc = dom.XmlDocument() xDoc.load_xml(tString) notifier.show(ToastNotification(xDoc)) if __name__ == "__main__" : print("打卡成功!" )
3.3 定时执行脚本
buaa.bat :
1 2 python daily_report.py python buaa_notice.py
如何配置,参考Dukou网站自动化签到
4 参考