本文章已过时
书接上回 -> URP教务系统自动登录
我可以用 GitHub Actions 写一个定时任务,每天早上把当天的空闲教室信息写进邮件发给我。
查询当天空闲教室 ¶
获取当天日期 ¶
这个说起来简单,但是还是有点坑,GitHub Actions 使用的 UTC 标准时间,我们这边的时区是 UTC+8,快8个小时,所以如果是早上8点之前执行的话,获取的还是昨天的信息。这里的时间要改。
定义三个函数,方便后续使用
# only for 2022-2023 1
def get_week_num(d=datetime.now(pytz.timezone('Asia/Shanghai'))):
return d.isocalendar().week - 34
# mon -> 1, ect..
def get_weekday(d=datetime.now(pytz.timezone('Asia/Shanghai'))):
return datetime.weekday(d) + 1
def get_format_date(d=datetime.now(pytz.timezone('Asia/Shanghai'))):
return d.strftime('%Y年%m月%d日')
这里我们使用 pytz
库来获取 Asia/Shanghai
时区的当前时间。
get_week_num()
函数用于获取当前的周数,这里的周数是学校的教学周,正好这学期2023年就没有教学周了,所以简单粗暴的相减即可get_weekday()
函数获取当前是一周的第几天
根据日期进行查询 ¶
定义每一小节的时间段
class_time = {
1: '第1节 08:00 08:45',
2: '第2节 08:50 09:35',
3: '第3节 09:50 10:35',
...
}
因为是每天的空闲教室信息,这里需要批量查询每一小节的教室使用情况。其他校区的同学可自行添加其他校区的信息。
def search_today(self):
campus_code = 3 # 校区代码
tea_codes = [61, 62] # 教学楼代码列表
week_num = util.get_weekday() # 周数
results = [] # 结果集
for tea_code in tea_codes:
classrooms = []
for i in range(1, 13):
section = str(week_num) + '/' + str(i) # 节数
param = {
'weeks': util.get_week_num(),
...
}
ret = self.search_free_classroom(param)
classroom = {
'time': class_time.get(i),
'rooms': ", ".join(ret),
}
classrooms.append(classroom)
results.append({
'tea': teaching_num.get(tea_code),
'classrooms': classrooms,
})
return results
创建邮件模板 ¶
这里是个大坑,一开始我不知道邮件HTML要求特别严格,有的邮件客户端甚至会过滤掉 <head>
里面的 <style>
外部样式
更多的内容可以参考阮一峰的博客 HTML Email 编写指南
我使用了 JinJa2 作为HMTL文件的模板渲染语言。
<h3 style="text-align: center;">空闲教室</h3>
<p style="text-align: center; padding-bottom: 20px; color: #586069">今日({{ daytime }})</p>
{% for result in results %}
<p style="margin-left: 20px">{{ result.tea }}空闲教室</p>
<table class="table table-striped table-bordered" border="1" style="border-collapse: collapse; margin-bottom: 30px">
<thead><tr>
<th class="content-block" style="width: 130px">节次</th>
<th>空闲教室</th>
</tr></thead>
<tbody>
{% for classroom in result.classrooms %}
<tr>
<td class="content-block" style="width: 130px"><p>{{ classroom.time }}</p></td>
<td style="color: #586069">{{ classroom.rooms }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endfor %}
渲染的内容包括两个方面:
daytime
: 当天时间的格式化字符串results
: 查询结果的Map对象
渲染模板部分的代码:
def write2html(params, template_file=TEMPLATE_FILE, html_file=HTML_FILE):
current_directory = os.path.dirname(os.path.abspath(__file__))
env = Environment(loader=FileSystemLoader(current_directory))
res = env.get_template(template_file).render(params)
test = codecs.open(html_file, 'w', 'utf-8')
test.write(res)
test.close()
函数 write2html()
接受待渲染的内容 params
,读取模板文件 template_file
,将内容输出到文件 html_file
中。
重构代码 ¶
为了方便测试和后续部署,这里我们的URP教务系统的用户名和密码不再硬编码到文件中,而是使用命令行参数的形式进行读取。
def parse_params():
parser = argparse.ArgumentParser()
parser.add_argument("-u", "--username", dest="username")
parser.add_argument("-p", "--password", dest="password")
args = parser.parse_args()
return args.__getattribute__('username'), args.__getattribute__('password')
运行时只需要使用下列命令即可
python main.py -u <username> -p <password>
添加定时任务 ¶
GitHub Actions makes it easy to automate all your software workflows, now with world-class CI/CD. Build, test, and deploy your code right from GitHub. Make code reviews, branch management, and issue triaging work the way you want.
我们可以在 GitHub Actions 上创建自己的 workflow ,命名为 send mail
更多关于 GitHub Actions 的内容,可以参考官方文档 https://docs.github.com/cn/actions
这里简单介绍一下构建流程:
- 拉取 ubuntu 镜像
- 切换到 actions 分支
- 创建 python 工作环境
- 安装依赖
- 执行 python 脚本
- 发送邮件
name: send mail
on:
schedule:
- cron: "20 22 * * *"
jobs:
build:
runs-on: ubuntu-latest
steps:
...
- name: install dependencies
run: |
pip install -r requirement.txt
- name: execute py script
run: |
python main.py -u $Username -p $Password
env:
Username: ${{ secrets.HHU_USERNAME }}
Password: ${{ secrets.HHU_PASSWORD }}
- name: send email
uses: dawidd6/action-send-mail@v2
with:
server_address: smtp.qcloudmail.com
server_port: 465
username: ${{ secrets.MAIL_USERNAME }}
password: ${{ secrets.MAIL_PASSWORD }}
subject: 今日空闲教室
body: file://template/result.html
to: ${{ secrets.EMAIL }}
from: GitHub Actions
content_type: text/html
为了防止密码泄露,我们还要在仓库添加5个密钥:
HHU_USERNAME
: URP 教务系统用户名HHU_PASSWORD
: URP 教务系统密码MAIL_USERNAME
: 邮箱服务发件邮箱MAIL_PASSWORD
: 邮箱服务发件邮箱授权密码EMAIL
: 收件邮箱
另外,根据不同的邮件服务,server_address
和 server_port
一般也不同,需要自行配置。我们将运行时间定为北京时间每天早上6:20,为了方便查看效果,测试时可以另外设置为 push
时触发。
差不多就是这样,每天早上起床就可以收到邮件,完美。
以上。