Skip to main content

4 posts tagged with "Python"

View All Tags

· 10 min read
Chengzihan

调用报平安接口并使用 GitHub Actions 自动完成北林每日报平安。本脚本 最大的特点是不需要你有一台一直开着的主机或者服务器,让 GitHub 完成这件事即可。

主逻辑来自 @Memory

食用指南

Fork 仓库

仓库地址https://github.com/inannan423/reportPeace

进入本仓库,点击右上角的 Fork 按钮,将本仓库 Fork 到自己的账号下。 顺便点击 star按钮收藏(为我点个赞)。

1

注意,此时这个仓库就是你的了,你在你的仓库密匙中填写的任何内容我均无法获取,请放心使用。

添加个人信息

在报平安代码中,有许多涉及隐私的东西。比如学号、密码、用户ID等。我们不希望这些东西在源代码被公开,所以我们需要把它们添加到 GitHub Secrets 中。

下面举一个例子:

在上面我们需要把学号存储为密匙,在代码中,它的变量名为 STUDENT_ID 。 打开你 Fork 后你的仓库。点击 Settings,然后点击 Secrets,点击 New repository secret,在 Name 中输入 STUDENT_ID,在 Value 中输入你的学号,点击 Add secret

2

3

4

5

然后点击添加。

按照上述步骤,你还需要添加下面内容,这些内容打开你平时报平安的界面,获取相同的即可:

STUDENT_ID # 学号,示例:201002401
PASSWORD # 密码,示例:abc123123123,也就是你的校园网密码
NAME # 姓名,示例:张三
SCHOOL # 学院,示例:信息学院
MAJOR # 专业,示例:计算机科学与技术
TYPE # 类型,示例:本科生 | 研究生
PHONE # 手机号,示例:12345678901
MASTER # 审核人,示例:李四
BUILDING # 宿舍楼栋,示例:11号楼
ROOM # 宿舍号,示例:901

以上添加完成后如图所示:

2

修改定时【可选】

yml 脚本中,我已经设置了每天 0:11 执行,为保证准确性,还添加了二次执行时间为早上 8:10. 不选择整点执行而选择在11分执行是为了避开高峰期。 你可以对其修改。在 .github/workflows 文件夹中,打开 main.yml 文件,修改 cron 的值即可。

name: autoReportPeace

on:
repository_dispatch:
types: [morning]
schedule:
- cron: '11 16,0 * * *'
# UTC 时间 16:11和 0:11对北京时间 0:11和 8:11
workflow_dispatch:
jobs:
#......

GitHub 采用世界标准时间,也就是 UTC 时间。北京时间是 UTC+8,因此北京时间比 UTC 时间早8小时。所以 UTC 0:00 对应的 北京 时间是 8:00。
也就是说,我们想要的时间减去8小时才是 UTC 时间。

corn的语法如下:

┌───────────── minute (0 - 59)
│ ┌───────────── hour (0 - 23)
│ │ ┌───────────── day of the month (1 - 31)
│ │ │ ┌───────────── month (1 - 12 or JAN-DEC)
│ │ │ │ ┌───────────── day of the week (0 - 6 or SUN-SAT)
│ │ │ │ │
│ │ │ │ │
│ │ │ │ │
* * * * *

例如,我们希望早上九点半执行,那么我们需要设置为 1:30:

corn: '30 1 * * *'

或者我们希望每天8:00和20:00执行:

corn: '0 0,12 * * *'

或者我们只希望每周三周五执行:

corn: '30 1 * * 3,5'

手动测试

除了定时测试外,我们还支持手动进行测试。你只需要打开 GitHub Action 界面。选中左侧的 autoReportPeace,点击右侧的下拉栏中的 Run workflow,即可手动执行。

2

3

接着,会有黄色的运行进程开始,直到进程变成蓝色的勾,表示运行成功。

3

延迟一到两分钟,你的微信会收到学校企业微信的报平安通知。表示部署成功,如果 不如预期,请检查上述步骤。

腾讯云加强定时【选做】

提高定时的准确性,可以不做。

但是有一个缺陷,就是 GitHub Action 的定时是不准确的,有时候会延迟十分钟甚至一两个小时。 不过我们通过两个时间点的定时,可以很大程度保证准确性。

2

Note: The event can be delayed during periods of high loads of GitHub Actions workflow runs. High load times include the start of every hour. To decrease the chance of delay, schedule your workflow to run at a different time of the hour.schedule

注意:在 GitHub Actions 工作流高负载运行期间,事件可能会延迟。高负载时间包括每小时的开始时等。为了减少延迟的可能性,请安排工作流在每小时的不同时间运行。

实测使用 GitHub Pages 的定时服务,延迟在 10 分钟到 1 小时不等,极端条件下定时不会执行

而 GitHub Actions 支持 workflow_dispatch 触发器(请参阅 GitHub Docs 上的触发工作流的事件,因此如果您手动触发工作流,它将立刻执行。这意味着您可以使用第三方 cron 调度服务,如 腾讯云、IFTTT、Google Cloud Scheduler 等,向 GithubAPI 发出请求以触发工作流。

那么这里将讲授一种使用腾讯云云函数定时触发的方法,增强其可靠性。如果你认为 GitHub定时两个时间点已经足够可靠,可以不再进行此操作

获取 GitHub Token

想要从远端操作 GitHub,我们需要一个 GitHub Token。

在你的 Github 主页,选择 setting
1
选择左下角的Developer settings
2
然后选择 Personal access tokens
3
填写相关信息,选择 无限期 , 勾选 repoworkflow 。点击创建。
4
然后生成完成,之后它会生成一串密码:
5
在你的 Github 主页,选择 setting
1
选择左下角的Developer settings
2
然后选择 Personal access tokens
3
填写相关信息,选择 无限期 , 勾选 repoworkflow 。点击创建。
4
然后生成完成,之后它会生成一串密码:
5

注意
请记住这一串密码,你将不再能看到它。

创建云函数

创建腾讯云函数

进入 腾讯云 并点击注册。可以使用微信登录。点击右上角进入控制台,搜索 云函数

2

点击新建云函数:

3

不选择模板,从头开始。

3

填写相关参数,选择环境 python

3

提高超时时间。

3

清空原有的代码,填入新的代码:

2

代码结构如下,你只需要修改 TOKEN (上面一步获取的) 这几参数以及 https://api.github.com/repos/你的用户名/reportPeace/dispatches 中的 GitHub 用户名即可。

# 腾讯云执行脚本,如不需要可忽略
import requests


def run():
headers = {
'Accept': 'application/vnd.github+json',
'Authorization': 'token 你的TOKEN',
# 注:'token' 前缀必不可少
}

data = '{"event_type": "autoReportPeace"}'

response = requests.post(f'https://api.github.com/repos/你的用户名/reportPeace/dispatches',
headers=headers, data=data)


# 云函数入口
def main_handler(event, context):
return run()

点击启用日志。

2

然后点击完成。进入详细界面的代码界面,点击测试。

3

查看下面的日志:

3

如果出现 204,则表示成功。其他状态码均为失败。

然后到 GitHub 仓库查看 Actions,可以看到已经成功触发了工作流。

2

勾变为蓝色,表示成功。

设置云函数定时触发

在侧边中创建定时:

2

点击创建触发器。

3

其中填写 Cron 表达式。

0 0 8 * * * *   # 每天 8 点
0 0 18 * * * * # 每天 18 点
0 0 7 * * 1-5 * # 周一到周五 7 点
0 30 6 * * * * # 每天 6 点半

点击提交后,会在每天指定时间触发执行。注意,腾讯云与 GitHub 不同,腾讯云 使用的是北京时间,这意味着你并不需要考虑时区问题。

一个函数而已,并不会消耗多少资源,所以不用担心。

· 20 min read
Chengzihan

前言

在上一篇博客中,我介绍了写好的爬取课程表的代码,但是这个代码只能在本地运行,但是现在我希望可以使用微信来进行课程提醒。但是配置服务器无疑是比较麻烦的,经过分析我发现定时任务和代码执行都可以使用 GitHub Action 执行。所以我就想到了使用 GitHub Actions 及 GitHub API 来实现这个功能。本篇文章将介绍如何使用我的代码实现课程与每日天气自动推送

涉及的工具和技术

  • Python
  • GitHub Actions
  • 微信公众平台开发
  • 腾讯云函数 SCF

GitHub Actions 介绍

1

GitHub Action 是 GitHub 提供的一项功能,可以在 GitHub 上运行自定义的脚本,可以用来自动化构建、测试、打包、发布或部署任何项目。GitHub Action 是 GitHub 为开发者提供的一项功能,可以在 GitHub 上运行自定义的脚本,可以用来自动化构建、测试、打包、发布或部署任何项目。

微信公众测试号

注册

我们要使用微信公众号来帮助我们传递消息。但是一般个人能注册的订阅号是不能满足我们的要求的,每天只能推送一条图文消息。但是微信为我们提供了测试号,测试号可以满足我们的需求,毕竟课表推送我们仅仅个人使用,不需要太多的人数。所以一个测试号就够了。

首先打开微信公众平台测试号注册。扫码登录后,点击立即开通,然后填写信息,就可以注册完成了。

扫码关注

在界面上找到二维码,让需要使用的用户扫码关注。

2

获取高德天气 API

不需要这个的可以跳过这一步。

注册

打开高德开放平台,点击右上角注册,然后填写信息,就可以注册完成了。

创建应用

注册成功后,打开控制台,在左侧选择应用管理,点击我的应用,然后在右上角选择创建新任务。应用名称和应用类型可以随意填写,然后点击创建

1

添加 Key

2

接着,填写信息,选择 Web 服务。然后点击提交。名称可以随便取。

2

记住这个生成的 Key ,之后会用到。

3

在 GitHub 上 Fork 本项目

打开本项目 仓库地址,点击右上角 Fork 并顺便点击 Star 纳入你的收藏,就可以将本项目全部代码复制到你的仓库中了。

2

然后,克隆源代码到你的本地。

在线编辑项目源代码

但是,实际上我们并不需要做过多修改,只需要一点点的参数修改就可以完成项目的构建了。那么,克隆在本地也就不再必要了,这里将为希望省事的人或者不会使用 Git 的人提供一个方法,直接在 GitHub 上修改代码。

GitHub 提供了一种能力叫做 GitHub Codespaces,可以在浏览器中直接修改代码,不需要下载任何东西。我们只需要把你刚刚克隆的仓库 <你的昵称>/wx_weather_class_push 中浏览器上方导航栏的链接中 github.com 改为 github.dev ,就可以启动在线 VScode ,便于你在浏览器中修改代码了。

https://github.com/<你的GitHub昵称>/wx_weather_class_push

修改后:

https://github.dev/<你的GitHub昵称>/wx_weather_class_push

启动过程,请稍等片刻:

2

启动成功,出现编辑器界面:

3

tip

右下角可能提示让你安装 Python 依赖,安装即可。

字太小了,我们可以把字体放大一点。点击左下角的设置图标。将文字大小设置为 20.可以按照自己的喜好设置。

1

修改配置

本项目提供了两种功能,可以每天早上道早安每天晚上道晚安同时在每节课开始前可以推送课程信息。这两个内容互相独立,可以只执行一个,也可以两者都执行。

修改早安推送代码

早安推送代码对应文件 morning.py。在左侧文件栏中找到 morning.py,点击打开。

2

在这个功能中,你只需要修改 user_id_list 即用户列表。

user_id_list = [
{
'user_id': user_id_1, # 用户 ID,不需要在这里修改
"name": 'Orange', # 用户昵称,可以修改,随便写
"date": "2021-04-02", # 纪念日,可以修改
"birthday": "05-28", # 生日,可以修改
"city": "110108" # 城市代码,可以修改,在高德 API 中查询
}
]

这里 可以查询你的城市的天气接口代码。

2

同时,你可以添加多个人,只需要在 user_id_list 中再添加一个字典即可。但是请注意,你需要添加一个新的 user_id 环境变量。

user_id_list = [
{
'user_id': user_id_1, # 用户 ID,不需要在这里修改
"name": 'Orange', # 用户昵称,可以修改,随便写
"date": "2021-04-02", # 纪念日,可以修改
"birthday": "05-28", # 生日,可以修改
"city": "110108" # 城市代码,可以修改,在高德 API 中查询
},
{
'user_id': user_id_2, # 用户 ID,不需要在这里修改
"name": 'Orange', # 用户昵称,可以修改,随便写
"date": "2021-04-02", # 纪念日,可以修改
"birthday": "05-28", # 生日,可以修改
"city": "110108" # 城市代码,可以修改,在高德 API 中查询
}
]

修改晚安推送代码

晚安代码对应 eve.py 在基础使用中,不需要修改。

修改课表信息代码

课表代码对应文件 classPush.py。在左侧文件栏中找到 classPush.py,点击打开。

修改用户列表

首先,同上,你可以修改 user_id_list 即用户列表。

2

修改学期信息

修改学年号和学期开始时间。除了下面高亮的两行( semesterfirstDay )外,其他不要修改。

id = os.environ["STUDENT_ID"]  # 学号
pwd = os.environ["PASSWORD"] # 密码
# 微信公众号 ID
app_id = os.environ["APP_ID"]
# 微信公众号 app_secret
app_secret = os.environ["APP_SECRET"]
semester = '2022-2023-1' # 学期
firstDay = '2022-08-29' # 学期开始日期
# ...省略

修改教务系统链接

tip

本套代码适用于强智教务系统,如果你的教务系统不是强智,请自行寻找 API 进行适配。

然后,你可以修改两个链接,将前面的前缀地址改为你学校的教务系统地址。即把 <http://newjwxt.bjfu.edu.cn/> 改为你学校的教务系统地址。后面的链接不要改动。

# ...省略其他代码
def Crawl():
loginLink = "http://newjwxt.bjfu.edu.cn/app.do?method=authUser&xh=" + id + "&pwd=" + pwd
rep = requests.get(loginLink)
res = json.loads(rep.text)
# 使用账号密码换取网站 token
token = res["token"]
tableUrl = "http://newjwxt.bjfu.edu.cn/app.do?method=getKbcxAzc&xh=" + id + "&xnxqid=" + semester + "&zc=" + week
header = {
"token": token # 传入 token ,鉴权
}
res = requests.get(url=tableUrl, headers=header)
schedule = json.loads(res.text) # 读取课表 json
# ...省略其他代码

修改每节课开始时间

这一步就稍微有点复杂了,不过也很好理解,我们需要判断当前时间在课表的哪个时间段,来判断现在应该要上哪一节课。

先获取现在的时间,由于我想要提前进行提醒,所以我把时间推迟20分钟,这样就可以提前20分钟提醒了。(就是说要去查询20分钟后的课程)

# 获取现在时间
now = datetime.datetime.now()
# 获取现在时间的小时和分钟
hour = now.hour
minute = now.minute + 20 # 查询20分钟后的课程
second = now.second
# 分钟加20后,可能需要进行进位,如果分钟大于60,小时加1,分钟减60
if minute >= 60:
hour += 1
minute -= 60

接着,我们要把处理好的时间转换成字符串,方便后面的比较。

# 如果小时小于10,前面加0
if hour<10:
nowTime = '0' + str(hour) + ':' + str(minute) + ':' + str(second)
else :
nowTime = str(hour) + ':' + str(minute) + ':' + str(second)
# 如果进位后时间为 24:00:00 ,则改为 00:00:00
if hour==24:
nowTime = '00' + ':' + str(minute) + ':' + str(second)

然后,我们要判断现在时间在课表的哪个时间段,来判断现在应该要上哪一节课。我们把课表的几个关键点创建为变量。例如,我们学校的时间表如下:

# 8:00-9:35 第1-2节
# 9:50-12:15 第3-5节
# 13:30-15:05 第6-7节
# 15:20-16:55 第8-9节
# 18:30-20:55 第10-12节

我们只需要记录开始时间。

dt1 = datetime.datetime.strptime('08:00:00', '%H:%M:%S')
dt2 = datetime.datetime.strptime('09:50:00', '%H:%M:%S')
dt3 = datetime.datetime.strptime('13:30:00', '%H:%M:%S')
dt4 = datetime.datetime.strptime('15:20:00', '%H:%M:%S')
dt5 = datetime.datetime.strptime('18:30:00', '%H:%M:%S')

但是,Github采用UTC时间,北京时间比UTC时间早8小时。所以我们必须把上述时间减去8小时。

dt1 = datetime.datetime.strptime('00:00:00', '%H:%M:%S')
dt2 = datetime.datetime.strptime('01:50:00', '%H:%M:%S')
dt3 = datetime.datetime.strptime('05:30:00', '%H:%M:%S')
dt4 = datetime.datetime.strptime('07:20:00', '%H:%M:%S')
dt5 = datetime.datetime.strptime('10:30:00', '%H:%M:%S')

将现在的时间(准确来说是二十分钟后的时间)存为变量。

dtNow = datetime.datetime.strptime(nowTime, '%H:%M:%S')

然后计算整个时间段的秒数。例如 8:00-9:35 的秒数为 95 * 60 = 5700,依此类推。用现在的时间减去课程开始的时间,如果结果大于 0 且小于这个时间段的秒数,那么就是在这个时间段。

if 0 <= (dtNow - dt1).seconds < 5700:
return 1
elif 0 <= (dtNow - dt2).seconds < 8700:
return 3
elif 0 <= (dtNow - dt3).seconds < 5700:
return 6
elif 0 <= (dtNow - dt4).seconds < 5700:
return 8
elif 0 <= (dtNow - dt5).seconds < 8700:
return 10
else:
return -1

添加 Secrets

在上面的代码中,有许多涉及隐私的东西。比如学号、密码、用户ID等。我们不希望这些东西在源代码被公开,所以我们需要把它们添加到 GitHub Secrets 中。

下面举一个例子:

在上面我们需要把学号存储为密匙,在代码中,它的变量名为 STUDENT_ID 。 打开你 Fork 后你的仓库。点击 Settings,然后点击 Secrets,点击 New repository secret,在 Name 中输入 STUDENT_ID,在 Value 中输入你的学号,点击 Add secret

2

3

4

5

然后点击添加。

按照上述步骤,你还需要添加下面内容:

APP_ID # 测试公众号的ID
APP_SECRET # 测试公众号的密匙
KEY # 高德应用的密匙
PASSWORD # 教务系统密码
STUDENT_ID # 学号
TEMPLATE_ID # 早安模板ID
TEMPLATE_ID_CLASS # 课表模板ID
TEMPLATE_ID_EVE # 晚安模板ID
TEMPLATE_ID_NOCLASS # 无课模板ID
USER_ID_1 # 用户1 ID
USER_ID_2 # 用户2 ID ,还有多个用户可以继续添加

获取 APP_ID 和 APP_SECRET

在微信公众平台测试账号页面,前面的就是 APP_ID,后面的就是 APP_SECRET

2

获取高德应用的密匙 KEY

就在上面的步骤中。

获取模板 ID

在微信公众平台测试账号页面创建模板。

2

目前,你按需可以创建四个模板。如下添加:

3

在这里我把全部模板提供给你,你也可以修改。

# 上课模板
20分钟后即将上课: 课程名称: {{kcmc.DATA}} 上课节数: {{sksj.DATA}} 上课地点: {{jsmc.DATA}} 课程教师: {{jsxm.DATA}} {{words.DATA}}
# 无课模板
一会没有课嗷,休息一会或者自习吧!
# 早安模板
早上好! 今天 {{cityname.DATA}} ,天气 {{weather.DATA}} ,温度 {{temperature.DATA}},风向 {{winddirection.DATA}},今天是我们第 {{love_days.DATA}} 天,距离生日还有 {{birthday_left.DATA}} 天! {{words.DATA}}
# 晚安模板
晚安! 月亮坠入不见底的河,星星垂眸惊动了舸。晚安~~ {{words.DATA}}

创建好模板后,在侧边栏复制模板 ID。填入 TEMPLATE_IDTEMPLATE_ID_CLASSTEMPLATE_ID_EVETEMPLATE_ID_NOCLASS 中。

提交代码

代码编写完后,点击左侧分支按钮。

2

然后在上面随意输入信息。然后点击上面的对勾提交。

2

当仓库首页出现提交信息说明提交成功了。

2

腾讯云定时服务

背景

实际上 GitHub Pages 本身就能实现定时服务。让我们看看官方文档是怎么说的:

2

Note: The event can be delayed during periods of high loads of GitHub Actions workflow runs. High load times include the start of every hour. To decrease the chance of delay, schedule your workflow to run at a different time of the hour.schedule

注意:在 GitHub Actions 工作流高负载运行期间,事件可能会延迟。高负载时间包括每小时的开始时等。为了减少延迟的可能性,请安排工作流在每小时的不同时间运行。

实测使用 GitHub Pages 的定时服务,延迟在 10 分钟到 1 小时不等,极端条件下定时不会执行。我们果断抛弃这个方式。

而 GitHub Actions 支持 workflow_dispatch 触发器(请参阅 GitHub Docs 上的触发工作流的事件,因此如果您手动触发工作流,它将立刻执行。这意味着您可以使用第三方 cron 调度服务,如 腾讯云、IFTTT、Google Cloud Scheduler 等,向 GithubAPI 发出请求以触发工作流。

获取 GitHub Token

在你的 Github 主页,选择 setting
1
选择左下角的Developer settings
2
然后选择 Personal access tokens
3
填写相关信息,选择 无限期 , 勾选 repoworkflow 。点击创建。
4
然后生成完成,之后它会生成一串密码:
5
在你的 Github 主页,选择 setting
1
选择左下角的Developer settings
2
然后选择 Personal access tokens
3
填写相关信息,选择 无限期 , 勾选 repoworkflow 。点击创建。
4
然后生成完成,之后它会生成一串密码:
5

注意

请记住这一串密码,你将不再能看到它。

创建腾讯云函数

进入 腾讯云 并点击注册。可以使用微信登录。点击右上角进入控制台,搜索 云函数

2

你需要创建三个云函数,分别是:morningeveningclass。下面以 morning 为例。

点击新建云函数:

3

不选择模板,从头开始。

3

填写相关参数,选择环境 python

3

提高超时时间。

3

清空原有的代码,填入新的代码:

2

代码结构如下,你只需要修改 TOKEN (上面一步获取的) 这几参数以及 https://api.github.com/repos/<YOUR GITHUB NAME>/wx_weather_class_push/dispatches 中的 GitHub 用户名即可。

import requests

def run():
headers = {
'Accept': 'application/vnd.github+json',
'Authorization': 'token <TOKEN>',
# 请把 <TOKEN> 替换为你的 GitHub Token
}
data = '{"event_type": "morning"}'

response = requests.post(f'https://api.github.com/repos/<YOUR GITHUB NAME>/wx_weather_class_push/dispatches', headers=headers, data=data)

# 云函数入口
def main_handler(event, context):
return run()

点击启用日志。

2

然后点击完成。进入详细界面的代码界面,点击测试。

3

查看下面的日志:

3

如果出现 204,则表示成功。其他状态码均为失败。

然后到 GitHub 仓库查看 Actions,可以看到已经成功触发了工作流。

2

勾变为蓝色,表示成功。

3

这时手机收到了推送。

2

然后,在侧边中创建定时:

2

点击创建触发器。

3

其中填写 Cron 表达式。

0 0 8 * * * *   # 每天 8 点
0 0 18 * * * * # 每天 18 点
0 0 7 * * 1-5 * # 周一到周五 7 点
0 30 6 * * * * # 每天 6 点半

点击提交后,会在每天指定时间触发执行。

你还需要完成两个云函数,分别是 eveningclass。可以参考上述步骤。其中课表推送需要多个触发器,参考如下:

3

3

3

这需要根据你的课程表自行修改。

在源代码仓库的 run.py 中,由上面三个函数的源码。

支持

如果你觉得这个项目对你有帮助,欢迎给我一个 Star。

仓库地址:wx_weather_class_push

· 16 min read
Chengzihan
danger

本脚本仅用于交流学习,不得用于其他用途,如果因为恶意使用本脚本造成的一切后果,与本人无关。

前言

又到了开学季,作为一个合格的大学生。每天我们都要上不同的课,前往不同的教室,需要我们一遍遍去查看课表。那么我们能不能编写一个脚本来帮我们自动获取课表呢?这篇文章就来说明我是如何使用Python爬取强智教务系统获取课表信息的。

获取课表接口

接口链接

强智系统是一个使用很广泛的系统,它的课表 API 也是统一的。经过抓包,找到了一个课表 API ,如下:

<前缀>/jsxsd/xskb/xskb_list.do?Ves632DSdyV=NEW_XSD_PYGL

但是!这个 API 返回的竟然是 html 代码。那就需要我们使用正则表达式来提取我们需要的信息了。但这也太麻烦了,应该有 json 的 API 吧!果不其然,我这就发现了一个:

<前缀>/app.do?method=getKbcxAzc&xh=<StudentID>&xnxqid=<Semester>&zc=<week>

注意,这是一个 POST 请求。<前缀> 代表你的学校的教务系统域名,请自行替换,如我的学校是:

http://newjwxt.bjfu.edu.cn/app.do?method=getKbcxAzc&xh=<StudentID>&xnxqid=<Semester>&zc=<week>

参数说明

  • method:固定为 getKbcxAzc
  • StudentID:学号
  • Semester:学期,格式为 2021-2022-1,其中 1 表示第一学期,2 表示第二学期
  • week:周次,从 1 开始

接口分析

现在,让我们使用 APIFOX 来分析一下这个 API 的返回值。填入学号、学期、周次,点击发送请求。

1

发送请求,返回值:

2

{
"token": "-1"
}

这告诉我们,这个 API 是需要鉴权的。那么我们就需要先登录,拿到 API 的鉴权 token ,然后再发送请求。

使用相同的方法获取登录 API ,如下:

<前缀>/app.do?method=authUser&xh=<StudentID>&pwd=<pwd>

参数说明

  • method:固定为 authUser
  • StudentID:学号
  • pwd:密码

同样,这是一个 POST 接口。填入学号密码,发送请求获取返回的 TOKEN

1

返回值:

{
"success": true,
"token": "eyJ0e...", // 这就是我们需要的 token
"user": {
"username": "你的姓名",
"userdwmc": "你所在的学院",
"usertype": "2",
"userpasswd": "你的密码",
"useraccount": "你的账号"
},
"usertype": "2",
"userrealname": "你的姓名",
"userdwmc": "你的学院"
}

复制返回值中的 TOKEN 值,填入课表 API 的请求参数中,发送请求。添加在 Header 中的 token 参数,如下:

2

再次发送请求,返回值:

2

这就是我们需要的课表数据 json 了。具体格式如下:

[
{
"jsxm": "教师姓名",
"jsmc": "上课教室",
"jssj": "课程开始时间",
"kssj": "课程结束时间",
"kkzc": "上课节数 第几到几节课",
"kcsj": "10102", // 课程时间
"kcmc": "数据库应用", // 课程名称
"sjbz": "0" // 未知
},
//...
]

分析各字段含义如下:

# "jsxm": "老师", // 教师姓名
# "jsmc": "一教101", // 教室名称
# "jssj": "9:35", // 结束时间
# "kssj": "08:00", // 开始时间
# "kkzc": "1", // 开课周次,有三种已知格式1)a - b、2)a, b, c、3)a - b, c - d
# "kcsj": "10102", // 课程时间,格式x0a0b,意为星期x的第a, b节上课
# "kcmc": "大学英语", // 课程名称
# "sjbz": "0" // 具体意义未知,据观察值为1时本课单周上,2时双周上

脚本编写

分析好 API 后,我们就可以开始编写脚本了。

创建 API 请求

首先我们必须创建 http 请求,这里我们使用 requests 库。并且我们要解析返回的 json 数据,这里我们使用 json 库。

import requests
import json

然后创建函数执行请求,实现上面我们登录获取 Token 和获取课表的 API 的步骤。为便于管理,将各个参数封装成变量放到脚本顶部,便于修改和调用。

id = '201002001'  # 学号
pwd = 'aaa111111' # 密码
semester = '2022-2023-1' # 学期

函数如下:

def Crawl():
# 登录 API
loginLink = "http://newjwxt.bjfu.edu.cn/app.do?method=authUser&xh=" + id + "&pwd=" + pwd
# 请求登录 API , 返回值为 json
rep = requests.get(loginLink)
# 解析 json
res = json.loads(rep.text)
# 获取返回值中的 token 字段值
token = res["token"]
# 课表 API
tableUrl = "http://newjwxt.bjfu.edu.cn/app.do?method=getKbcxAzc&xh=" + id + "&xnxqid=" + semester + "&zc=" + week
# 传入 token 参数
header = {
"token": token # 鉴权
}
# 请求课表 API ,res 就是我们需要的课表数据
res = requests.get(url=tableUrl, headers=header)
schedule = json.loads(res.text) # 读取课表 json
# 打印课表
print(schedule)

获取当前周次

我们想要的是完全自动化,每周手动改脚本算什么?!因此,我们来获取当前周次。要使用时间模块,我们需要先导入 datetime 模块。

import datetime

脚本:

# 判断当前日期所在周数
def getWeek():
# 获取现在时间
now = datetime.datetime.now()
# 第一周
firstWeek = datetime.datetime.strptime(firstDay, '%Y-%m-%d')
# 当前周数, 从第一周开始
week = (now - firstWeek).days // 7 + 1
print("第" + str(week) + "周")
return week

获取今天星期几

课表是按照星期几排布的,所以我们需要获取今天是星期几。函数也很简单,如下:

# 判断今天星期几
def getWeekDay():
d = datetime.datetime.now()
weekd = d.weekday() + 1
print("星期" + str(weekd))
return int(weekd)

获取现在的时间应该在上哪节课

这一步就稍微有点复杂了,不过也很好理解,我们需要判断当前时间在课表的哪个时间段,来判断现在应该要上哪一节课。

先获取现在的时间,由于我想要提前进行提醒,所以我把时间推迟20分钟,这样就可以提前20分钟提醒了。(就是说要去查询20分钟后的课程)

# 获取现在时间
now = datetime.datetime.now()
# 获取现在时间的小时和分钟
hour = now.hour
minute = now.minute + 20 # 查询20分钟后的课程
second = now.second
# 分钟加20后,可能需要进行进位,如果分钟大于60,小时加1,分钟减60
if minute >= 60:
hour += 1
minute -= 60

接着,我们要把处理好的时间转换成字符串,方便后面的比较。

# 如果小时小于10,前面加0
if hour<=10:
nowTime = '0' + str(hour) + ':' + str(minute) + ':' + str(second)
else :
nowTime = str(hour) + ':' + str(minute) + ':' + str(second)
# 如果进位后时间为 24:00:00 ,则改为 00:00:00
if hour==24:
nowTime = '00' + ':' + str(minute) + ':' + str(second)

然后,我们要判断现在时间在课表的哪个时间段,来判断现在应该要上哪一节课。我们把课表的几个关键点创建为变量。例如,我们学校的时间表如下:

# 8:00-9:35 第1-2节
# 9:50-12:15 第3-5节
# 13:30-15:05 第6-7节
# 15:20-16:55 第8-9节
# 18:30-20:55 第10-12节

我们只需要记录开始时间。

dt1 = datetime.datetime.strptime('08:00:00', '%H:%M:%S')
dt2 = datetime.datetime.strptime('09:50:00', '%H:%M:%S')
dt3 = datetime.datetime.strptime('13:30:00', '%H:%M:%S')
dt4 = datetime.datetime.strptime('15:20:00', '%H:%M:%S')
dt5 = datetime.datetime.strptime('18:30:00', '%H:%M:%S')

将现在的时间(准确来说是二十分钟后的时间)存为变量。

dtNow = datetime.datetime.strptime(nowTime, '%H:%M:%S')

然后计算整个时间段的秒数。例如 8:00-9:35 的秒数为 95 * 60 = 5700,依此类推。用现在的时间减去课程开始的时间,如果结果大于 0 且小于这个时间段的秒数,那么就是在这个时间段。

if 0 <= (dtNow - dt1).seconds < 5700:
return 1
elif 0 <= (dtNow - dt2).seconds < 8700:
return 3
elif 0 <= (dtNow - dt3).seconds < 5700:
return 6
elif 0 <= (dtNow - dt4).seconds < 5700:
return 8
elif 0 <= (dtNow - dt5).seconds < 8700:
return 10
else:
return -1

该函数的完整代码:

Details
# 判断当前所在第几节课
def getNowClass():
# 获取现在时间
now = datetime.datetime.now()
# 获取现在时间的小时和分钟
year = now.year
hour = now.hour
minute = now.minute + 20
second = now.second
# 如果分钟大于60,小时加1,分钟减60
if minute >= 60:
hour += 1
minute -= 60
# 拼接为时间格式
if hour <= 10:
nowTime = '0' + str(hour) + ':' + str(minute) + ':' + str(second)
else:
nowTime = str(hour) + ':' + str(minute) + ':' + str(second)

if hour == 24:
nowTime = '00' + ':' + str(minute) + ':' + str(second)
# 判断当前时间所在第几节课
# 如果当前时间位于 8:00 到 9:35 之间,返回 1
dt1 = datetime.datetime.strptime('08:30:00', '%H:%M:%S')
dt2 = datetime.datetime.strptime('09:50:00', '%H:%M:%S')
dt3 = datetime.datetime.strptime('13:30:00', '%H:%M:%S')
dt4 = datetime.datetime.strptime('15:20:00', '%H:%M:%S')
dt5 = datetime.datetime.strptime('18:30:00', '%H:%M:%S')
dtNow = datetime.datetime.strptime(nowTime, '%H:%M:%S')
# print((dtNow - dt1).seconds)
if 0 <= (dtNow - dt1).seconds < 5700:
return 1
elif 0 <= (dtNow - dt2).seconds < 8700:
return 3
elif 0 <= (dtNow - dt3).seconds < 5700:
return 6
elif 0 <= (dtNow - dt4).seconds < 5700:
return 8
elif 0 <= (dtNow - dt5).seconds < 8700:
return 10
else:
return -1

解析 json 为列表字典

现在我们要将 json 数据按照星期几第几节课进行解析,存为列表。由于我们的 json 每条数据的格式为:

{'jsxm': '无', 'jsmc': '无', 'jssj': '00:00', 'kssj': '00:00', 'kkzc': '0', 'kcsj': '00000', 'kcmc': '本节无课','sjbz': '0'}

那我们就可以初始化一个二维列表,每个元素都是一个上面的模板值。

table = [[{'jsxm': '无', 'jsmc': '无', 'jssj': '00:00', 'kssj': '00:00', 'kkzc': '0', 'kcsj': '00000', 'kcmc': '无课',
'sjbz': '0'} for i in range(1, 100)] for j in range(1, 100)]
列表推导

这是 Python 语法中一个列表推导(List Comprehension)的例子,可以用来初始化一个列表。

arr = [0 for i in range(1000)]

for 前面的 0 表示列表中的每个元素都是 0for 后面的 i 表示循环变量,range(1000) 表示循环 1000 次。同理,也可以举一反三初始化一个字符串列表:

arr = ['' for i in range(1000)]

它们的区别只是 for 前面的值不同。同理,也可以初始化一个字典列表:

arr = [{'name': '无', 'age': 0} for i in range(1000)]

现在,我们可以把 schedule 变量中的数据按照星期几第几节课进行解析,存为列表了。

等一下,怎么获取这节课是星期几上的呢?别急,我们来复习一下 课表json 的结构。

# "jsxm": "老师", // 教师姓名
# "jsmc": "一教101", // 教室名称
# "jssj": "9:35", // 结束时间
# "kssj": "08:00", // 开始时间
# "kkzc": "1", // 开课周次,有三种已知格式1)a - b、2)a, b, c、3)a - b, c - d
# "kcsj": "10102", // 课程时间,格式x0a0b,意为星期x的第a, b节上课
# "kcmc": "大学英语", // 课程名称
# "sjbz": "0" // 具体意义未知,据观察值为1时本课单周上,2时双周上

仔细看看 kcsj 这个字段,它的格式是 x0a0b,意为星期 x 的第 a, b 节上课。那么我们提取出这个字段的第一个数,不就是星期几了吗,获取到第二、三个数,不就是第几节课了吗。

"kcsj": "10102" 标识周1第1、2节课上课,那么我们就可以把这个课程信息存到 table[1][1]中。

i['kcsj'][1] # 第二个数 下标从0开始,在10102中为0
i['kcsj'][2] # 第三个数 下标从0开始,在10102中为1

然后将其拼接并转为整数:

classNum = int(i['kcsj'][1] + i['kcsj'][2])

这一部分的完整代码:

# 将 schedule 中的课程信息赋值给 table
for i in schedule:
# 课程的节数
classNum = int(i['kcsj'][1] + i['kcsj'][2])
# 将课程信息写入列表
# 课程在星期几
wd = int(i['kcsj'][0])
table[wd][classNum] = i

查询当前课程

获取现在的星期和节数,就可以从 table 中查询到当前上的课了。

def QueryClass():
nowClass = getNowClass() # 获取当前节数
nowWd = getWeekDay() # 获取当前星期几
if nowClass == -1:
print("当前无课")
else:
print("当前第" + str(nowClass) + "节课")
print(table[nowWd][nowClass])
return table[nowWd][nowClass]

脚本仓库

已开源:代码地址

运行结果

2

应用

使用此脚本,你可以将其部署到你的服务器,推送到微信,或者使用此接口编写课表小程序。

安全提示

danger

本脚本涉及隐私(包含学号和密码)使用时请自己部署自己使用,不要泄露给他人。如果要分享脚本,请删除上述信息。

支持我

如果您觉得这篇文章有帮到您,请到 GitHub 为我留下一颗 ⭐ 。

· 2 min read
Chengzihan

前言

生活中,我们常常会拿起以前的老照片。但是随着时间的推移,照片被严重氧化失去了原本的颜色。本文将介绍使用百度的API实现老照片上色。

一、注册百度开发者账号

打开百度AI开放平台,点击“注册”,填写账号信息,注册成功.注册成功后选择开放能力-黑白图像上色,开通此项能力。
1654515327656.png
打开应用列表,创建应用。
1654515492431.png
记录你的API key和Secret Key。
1654515631801.jpg

二、编码

创建Python工程,输入以下的代码:

import base64
import requests

# client_id 为官网获取的API key, client_secret 为官网获取的secret key
host = 'https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id=你的AK&client_secret=你的SK'
response = requests.get(host)
if response:
print(response.json())

# 黑白图像上色
request_url = "https://aip.baidubce.com/rest/2.0/image-process/v1/colourize"
# 二进制方式打开图片文件
f = open('test.png', 'rb')
img = base64.b64encode(f.read())

params = {"image":img}
access_token = response.json()['access_token']
request_url = request_url + "?access_token=" + access_token
headers = {'content-type': 'application/x-www-form-urlencoded'}
response = requests.post(request_url, data=params, headers=headers)
if response:
print(response.json())

# base64编码转图片
img = base64.b64decode(response.json()['image'])
file = open('result.jpg', 'wb')
file.write(img)
file.close()

运行代码,输出图片,对比如下:
处理前:
1.png
处理后:
result.jpg
(图片来源于网络,侵删)

备注

好像免费的只能调用一次,你可以再去领取,否则免费余额用光后会报错。

参考文章地址