前言
开学以来,学校一直都要求每日疫情上报,时常会忘记。为了更好地配合学校工作,按时上报,在室友的提醒下,想到写一个python脚本完成此任务。
完成方式主要两种。
方法一直接用 selenium 模拟浏览器操作实现动态HTML处理,完成报送。
方法二是根据数据特征直接封装有效的post包发至目标服务器,实现信息报送,并监听服务器响应。
方法一其实是属于“半自动化”,存在一些弊端,但是实现简单,本着以最快的最容易
理解的方式编写程序,选用此法。
方法二是最好的实现方式,但是较为复杂,教程可参考:疫情期间每日健康报送任务的自动化处理
1、疫情上报(以哈工大(深圳)为例)
1.1 安装selenium
Selenium 是一个用于Web应用程序测试的工具。Selenium测试直接运行在浏览器中,就像真正的用户在操作一样。支持的浏览器包括IE,Mozilla Firefox,Safari,Google Chrome,Opera,Edge等。
安装方法:win+r 输入cmd,然后安装selenium:
pip install selenium
可以通过下面命令,查看selenium信息,确认已经安装完毕。
pip show selenium
安装过程截图如下,我已安装selenium,故输入第一个命令时会显示已安装。
很多人学习python,不知道从何学起。
很多人学习python,掌握了基本语法过后,不知道在哪里寻找案例上手。
很多已经做案例的人,却不知道如何去学习更加高深的知识。
那么针对这三类人,我给大家提供一个好的学习平台,免费领取视频教程,电子书籍,以及课程的源代码!
QQ群:705933274
1.2安装webdriver浏览器驱动(以Egde为例)
a.)首次按打开网页设置,查看Egde浏览器版本号。
b.) 点击msedgedriver.exe下载链接,下载对应版本号的浏览器驱动。一般都是64位操作系统,点击x64进行下载。
c.)下载解压后将msedgedriver.exe拷贝到浏览器安装文件夹(桌面右击浏览器图标,打开文件位置即可找到),记住msedgedriver.exe文件位置,后面程序中设置会用到。
(注:另外一种方法,将其加入环境变量的path,程序中就不用设定,暂不介绍。)
1.3 代码介绍
本着以简单快捷的方式完成哈工大(深圳)疫情上报,在此只介绍关键部分,其他学校或者对相关内容感兴趣的同学可做深层次了解,以便修改完善功能。此部分代码实现的功能是疫情上报,并将截图保存至文件夹中,用于下一部分的邮件发送。
a.)需要修改的部分(代码10、11行):
输入学号和密码,可支持输入多个同学的学号与密码。实现多人上报。
stu_number = ['20S153xxx(1)', '20S153xxx(2)', '20S153xxx(3)', '20S153xxx(4)'] # 输入不同同学的学号,需修改
stu_password = ['xxxxx(1)', 'xxxxx(2)', 'xxxxx(3)', 'xxxxx(4)'] # 输入不同同学的密码,需修改
修改浏览器驱动存放的位置(代码17行):
driver_url = r"C:\Program Files (x86)\Microsoft\Edge\Application\msedgedriver.exe" # 输入webdriver放置的路径
注:其他学校的同学要修改上报官网(代码20行)。
# 进入疫情上报官网,根据学校上报网址进行修改。
driver.get("https://sso.hitsz.edu.cn:7002/cas/login?service=http%3A%2F%2Fxgsm.hitsz.edu.cn%2Fzhxy-xgzs%2Fcommon%2FcasLogin%3Fparams%3DL3hnX21vYmlsZS94c0hvbWU%3D")
b.) 部分代码介绍:
程序中很关键的部分是找到对应的元素,并进行点击、输入或修改等相关的操作。
在本程序中用到了以下几种:
1.id定位:find_element_by_id(“id值”);id属性是唯一的
2.class定位:元素的类名,find_element_by_class_name(“class值”)
3.link定位:专门用来定位文本链接,find_element_by_link_name(“text”);
4.XPath定位:find_element_by_xpath(""),分为绝对定位和相对定位。
在登陆界面使用的是id和class定位,打开网页,按F12查看网页源代码,查找相应位置。
对应代码如下,send_keys()用于输入信息,click()模拟点击:
username = driver.find_element_by_id('username') # 学号定位
username.send_keys(stu_number[i]) # 输入学号
password = driver.find_element_by_id('password') # 密码定位
password.send_keys(stu_password[i]) # 输入密码
driver.find_element_by_id('rememberMe').click() # 点击记住密码
driver.find_element_by_class_name('landing_btn_bg').click() # 登录
第二个界面,点击每日上报,使用link定位:
对应代码:
driver.find_element_by_partial_link_text('每日上报').click()
第三个界面的新增元素,采用的是xpath相对定位。
对应代码:
driver.find_element_by_xpath('//*[@class="weui-btn_cell weui-btn_cell-primary open-popup"]/div[1]').click() # 点击新增
time.sleep(5) # 注意程序延时问题,时间短导致未提交就已经退出了。
第四个界面填报相关信息,由于哈工大(深圳)填报后会有之前的记录,所以直接提交即可。使用id定位和XPath绝对定位。
对应代码:
# 因为哈工大会自动记录上一天的信息,所以不需要填报其他信息可直接提交
driver.find_element_by_id('txfscheckbox').click() # 我已仔细阅读并同意
time.sleep(1)
driver.find_element_by_xpath('/html/body/div[5]').click()
time.sleep(5) # 延时,完成后界面返回进行截图。
此后的操作便是截图保存。详细信息见第四部分-整体代码
2、SMTP发送邮件(QQ邮箱为例)
此部分实现的功能的是使用SMTPF发送邮件,并将疫情上报截图发送到对应同学邮箱。
SMTP(Simple Mail Transfer Protocol)即简单邮件传输协议,它是一组用于由源地址到目的地址传送邮件的规则,由它来控制信件的中转方式。
python的smtplib提供了一种很方便的途径发送电子邮件。它对smtp协议进行了简单的封装。
2.1需要修改的部分
from_address = '[email protected]' # 发送方邮箱(自己的邮箱)
password_email = 'xxxxxxxx' # 进入qq邮箱->设置->账户->找到stmp服务,点击开启。验证后会给你一个授权码,直接复制,填入下方即可
to_address = ['xxx(1)@qq.com', 'xxx(2)@qq.com', 'xxx(3)@qq.com', 'xxx(4)@qq.com'] # 收信方邮箱
QQ邮箱授权码获取方式如下,进入qq邮箱->设置->账户->找到stmp服务,点击开启:
邮件发送的内容是:文字+图片+附件。具体的代码介绍见第四部分-整体代码,有详细注释。
2.2 效果图
3、设置为定时上报
由于没有服务器,所以只有定时开机+计划任务的方式执行python脚本。
3.1 win10设定计划任务执行python
不重复介绍,参看教程:win10计划任务定时启动python程序注意设置之后要勾选使用最高权限,不然不能访问截图:
任务截图:
3.2 定时开机需要进入bios
前提是bios支持电源管理(每个主板bios设置不同)参看教程:怎样让电脑定时开机
4.整体代码
哈工大(深圳)的同学修改账户邮箱信息后直接使用,可实现单人或者多人疫情上报。有两点需要特别注意:
1.点击新增后的延时程序时间一定够,否则会显示未提交;
2.工大每天只能上报一次,请慎重进行代码测试。
from selenium import webdriver
import time
from pathlib import Path
import smtplib
from email.mime.multipart import MIMEMultipart # 构建多个元素
from email.mime.image import MIMEImage # 构建邮件图片
from email.mime.text import MIMEText # 构建邮件文本
from email.header import Header # 调用header文件
# 需要修改的部分
stu_number = ['20S153xxx(1)', '20S153xxx(2)', '20S153xxx(3)', '20S153xxx(4)'] # 输入不同同学的学号,需修改
stu_password = ['xxxxx(1)', 'xxxxx(2)', 'xxxxx(3)', 'xxxxx(4)'] # 输入不同同学的密码,需修改
stu_name = ['xxx(1)', 'xxx(2)', 'xxx(3)', 'xxx(4)'] # 附件加上同学名字首写字母前缀,用以区分。不必须
from_address = '[email protected]' # 发送方邮箱(自己的邮箱)
password_email = 'xxxxxxxx' # 进入qq邮箱->设置->账户->找到stmp服务,点击开启。验证后会给你一个授权码,直接复制,填入下方即可
to_address = ['xxx(1)@qq.com', 'xxx(2)@qq.com', 'xxx(3)@qq.com', 'xxx(4)@qq.com'] # 收信方邮箱
for i in range(len(stu_number)):
driver_url = r"C:\Program Files (x86)\Microsoft\Edge\Application\msedgedriver.exe" # 输入webdriver放置的路径
driver = webdriver.Edge(executable_path=driver_url)
# 进入疫情上报官网,根据学校上报网址进行修改。
driver.get("https://sso.hitsz.edu.cn:7002/cas/login?service=http%3A%2F%2Fxgsm.hitsz.edu.cn%2Fzhxy-xgzs%2Fcommon%2FcasLogin%3Fparams%3DL3hnX21vYmlsZS94c0hvbWU%3D")
driver.maximize_window() # 最大化窗口
# 登录信息
time.sleep(1)
username = driver.find_element_by_id('username') # 学号定位
username.send_keys(stu_number[i]) # 输入学号
password = driver.find_element_by_id('password') # 密码定位
password.send_keys(stu_password[i]) # 输入密码
driver.find_element_by_id('rememberMe').click() # 点击记住密码
driver.find_element_by_class_name('landing_btn_bg').click() # 登录
time.sleep(1)
driver.find_element_by_partial_link_text('每日上报').click()
time.sleep(1)
driver.find_element_by_xpath('//*[@class="weui-btn_cell weui-btn_cell-primary open-popup"]/div[1]').click() # 点击新增
time.sleep(5) # 注意程序延时问题,时间短导致未提交就已经退出了。
# 因为哈工大会自动记录上一天的信息,所以不需要填报其他信息可直接提交
driver.find_element_by_id('txfscheckbox').click() # 确认
time.sleep(1)
driver.find_element_by_xpath('/html/body/div[5]').click()
time.sleep(5) # 延时,完成后界面返回进行截图。
current_time = time.strftime(stu_name[i]+"%Y-%m-%d-%H_%M_%S", time.localtime(time.time())) # 记录截图时间,并以该时间命名
filename = u'.\\image' # 新创建路径“.”表示当前整个.py文件的路径所在的位置,“\\”路径分割符,其中的一个是"\"转义符
pic_path = filename + '\\' + current_time + '.png'
if Path(filename).is_dir(): # 判断文件夹是否存在,不存在就新建一个新的
pass
else:
Path(filename).mkdir()
time.sleep(2)
driver.save_screenshot(pic_path) # 截取当前url页面的图片,并且将截取的图片保存在指定的路径并以截图时间命名)
print(pic_path) # 打印路径
time.sleep(1)
driver.close() # 关闭网页
# 发信服务器
msg = MIMEMultipart('related') # mixed -- 混合型 alternative--文本混合 related--多媒体元素
# 邮件头信息
msg['From'] = Header(from_address)
msg['To'] = Header(to_address[i])
msg['Subject'] = Header('每日疫情填报情况', 'utf-8')
# 开启发信服务,这里使用的是加密传输
# 正文-图片 通过html格式来放图片,可通过cid 编号实现上传多个图片
mail_msg = '''
<p>今日疫情上报,无需回复。</p>
<p>\n\t 上报截图:</p>
<p><img src="cid:image1"></p>
'''
msg.attach(MIMEText(mail_msg, 'html', 'utf-8'))
# 添加图片
file = open(pic_path, "rb")
img = MIMEImage(file.read())
file.close()
img.add_header('Content-ID', '<image1>')
msg.attach(img) # 正文添加图片
# 下面的代码是上传附件,不必须,正文中有图片就可以注释掉。
file = open(pic_path, "rb")
img = MIMEImage(file.read())
file.close()
img.add_header('Content-Disposition', 'attachment', filename=current_time+'疫情上报.png')
msg.attach(img) # 正文添加附件
smtp_server = 'smtp.qq.com' # 选择用QQ邮箱发送
server = smtplib.SMTP_SSL(smtp_server)
server.connect(smtp_server, 465) # 465 为 SMTP 端口号
server.login(from_address, password_email) # 登录发信邮箱
server.sendmail(from_address, to_address[i], msg.as_string()) # 发送邮件
server.quit() # 关闭服务器
5、不足
a.)没有服务器,只能采取定时开机+计划任务的方法执行程序。
b.)每日上报的信息一样,比如温度,程序中未修改体温,而是使用以前填写的体温,直接上报。感兴趣的同学可以增加此功能。
c.)此实现方法只能算“半自动化”,存在需要webdriver等环境依赖,体积大,运行慢,不便封装;每次报送需定位,过程慢,容错率低,且不支持异地主机自动化处理;明文存储账户信息等缺点,若感兴趣且有时间可用发送报文的方式实现。