├── .github └── workflows │ └── sync.yml ├── .gitignore ├── LICENSE ├── README.md ├── bath ├── go │ ├── README.md │ ├── main.go │ └── tokens.txt └── python │ ├── README.md │ └── bath.py ├── check ├── README.md ├── check.crontab.bash ├── check.py └── users.txt ├── crontab.bash ├── leave ├── README.md ├── index.html ├── leave.crontab.bash ├── leave.py └── users.txt └── requirements.txt /.github/workflows/sync.yml: -------------------------------------------------------------------------------- 1 | name: Sync to Gitee 2 | on: 3 | push: 4 | branches: 5 | - master 6 | jobs: 7 | sync: 8 | name: Sync to Gitee 9 | runs-on: ubuntu-latest 10 | steps: 11 | - name: Sync to Gitee 12 | uses: wearerequired/git-mirror-action@master 13 | env: 14 | SSH_PRIVATE_KEY: ${{ secrets.GITEE_PRIVATE_KEY }} 15 | with: 16 | source-repo: "git@github.com:OhYee/bupt-scripts.git" 17 | destination-repo: "git@gitee.com:OhYee/bupt-scripts.git" 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.log -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 OhYee 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 北邮脚本汇总 2 | 3 | [![Sync to Gitee](https://github.com/OhYee/bupt-scripts/workflows/Sync%20to%20Gitee/badge.svg)](https://gitee.com/OhYee/bupt-scripts) 4 | 5 | 各种可能用得到的脚本,由于大部分每天都要点,尽管都不需要抢,但是很麻烦,所以用脚本实现自动化。 6 | 7 | 各脚本的解释见对应的 README 8 | 9 | - [浴室预约 (Python 版)](./bath/python) 10 | - [浴室预约 (Go 版)](./bath/go) 11 | - [疫情防控通打卡](./check) 12 | - [临时出入校申请](./leave) -------------------------------------------------------------------------------- /bath/go/README.md: -------------------------------------------------------------------------------- 1 | # Go 语言版浴室预约脚本 2 | 3 | 该版本是为了编译出可以在路由器运行的自动预约程序而写的 4 | 5 | Go 交叉编译见 [将 Go 程序编译至 OpenWRT](https://www.oyohyee.com/post/note_compile_go_to_openwrt) 6 | 7 | ## 使用 8 | 9 | ``` 10 | -d 调试模式 11 | -debug 12 | 调试模式 13 | -s 预约模式 14 | -submit 15 | 预约模式 16 | -t string 17 | Token 文件路径 18 | -tokens string 19 | Token 文件路径 20 | ``` 21 | 22 | 使用`-t`指定存储用户信息的文件,一行一个,内容为对应用户在预约系统的 cookies 字段 23 | 24 | 默认运行为保持 Token 模式,程序会按顺序访问对应页面,保持 Token 有效(建议每小时运行一次)**目前该保活机制已失效** 25 | 26 | 添加`-s`参数,使用预约模式。默认会预约次日 21:00:00 浴室 2 楼 -------------------------------------------------------------------------------- /bath/go/main.go: -------------------------------------------------------------------------------- 1 | //go:generate bash -c "GOOS=linux GOARCH=mipsle GOMIPS=softfloat go build -o bupt_bath" 2 | 3 | package main 4 | 5 | import ( 6 | "flag" 7 | "fmt" 8 | "io/ioutil" 9 | "net/http" 10 | "net/url" 11 | "regexp" 12 | "strings" 13 | "time" 14 | ) 15 | 16 | const ( 17 | UserAgent = "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.116 Safari/537.36 QBCore/4.0.1301.400 QQBrowser/9.0.2524.400 Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2875.116 Safari/537.36 NetType/WIFI MicroMessenger/7.0.5 WindowsWechat" 18 | ContentType = "application/x-www-form-urlencoded" 19 | ) 20 | 21 | var ( 22 | idReg, _ = regexp.Compile("
学工号: (\\d+)
") 23 | infoReg, _ = regexp.Compile("
(.*)
") 24 | DEBUG = false 25 | ) 26 | 27 | // Get 请求到指定链接 28 | func Get(url string, userAgent string, cookie string) (status int, body []byte, err error) { 29 | client := http.Client{} 30 | req, err := http.NewRequest("GET", url, nil) 31 | if err != nil { 32 | return 33 | } 34 | 35 | req.Header.Set("User-Agent", userAgent) 36 | req.Header.Set("Cookie", cookie) 37 | 38 | resp, err := client.Do(req) 39 | if err != nil { 40 | return 41 | } 42 | defer resp.Body.Close() 43 | status = resp.StatusCode 44 | body, err = ioutil.ReadAll(resp.Body) 45 | if err != nil { 46 | return 47 | } 48 | return 49 | } 50 | 51 | // Post 请求到指定链接 52 | func Post(url string, data url.Values, userAgent string, cookie string) (status int, body []byte, err error) { 53 | client := http.Client{} 54 | req, err := http.NewRequest("POST", url, strings.NewReader(data.Encode())) 55 | if err != nil { 56 | return 57 | } 58 | 59 | req.Header.Set("User-Agent", userAgent) 60 | req.Header.Set("Cookie", cookie) 61 | req.Header.Set("Content-Type", ContentType) 62 | 63 | resp, err := client.Do(req) 64 | if err != nil { 65 | return 66 | } 67 | defer resp.Body.Close() 68 | 69 | status = resp.StatusCode 70 | body, err = ioutil.ReadAll(resp.Body) 71 | if err != nil { 72 | return 73 | } 74 | 75 | return 76 | } 77 | 78 | // Send 发送预约请求 79 | func Send(period string, token string) (status int, id string, info string, err error) { 80 | values := make(url.Values) 81 | values.Set("period", period) 82 | 83 | status, body, err := Post("http://wx.bupt.edu.cn/bathroom/submit", values, UserAgent, token) 84 | if err != nil { 85 | return 86 | } 87 | if DEBUG { 88 | fmt.Printf("%s\n", body) 89 | } 90 | 91 | _id := idReg.FindSubmatch(body) 92 | if len(_id) > 1 { 93 | id = string(_id[1]) 94 | } 95 | _info := infoReg.FindSubmatch(body) 96 | if len(_info) > 1 { 97 | info = string(_info[1]) 98 | } 99 | 100 | return 101 | } 102 | 103 | // Keep 用户 token 保活 104 | func Keep(token string) (status int, id string, err error) { 105 | status, body, err := Get("http://wx.bupt.edu.cn/bathroom/index", UserAgent, token) 106 | if err != nil { 107 | return 108 | } 109 | if DEBUG { 110 | fmt.Printf("%s\n", body) 111 | } 112 | 113 | _id := idReg.FindSubmatch(body) 114 | if len(_id) > 1 { 115 | id = string(_id[1]) 116 | } 117 | 118 | return 119 | } 120 | 121 | func read(file string) (tokens []string, err error) { 122 | tokens = make([]string, 0) 123 | data, err := ioutil.ReadFile(file) 124 | if err != nil { 125 | return 126 | } 127 | temp := strings.Split(string(data), "\n") 128 | for _, item := range temp { 129 | if item != "" { 130 | tokens = append(tokens, item) 131 | } 132 | } 133 | 134 | return 135 | } 136 | 137 | func main() { 138 | var debug bool 139 | var tokenFile string 140 | var submit bool 141 | flag.BoolVar(&debug, "debug", false, "调试模式") 142 | flag.BoolVar(&debug, "d", false, "调试模式") 143 | flag.BoolVar(&submit, "submit", false, "预约模式") 144 | flag.BoolVar(&submit, "s", false, "预约模式") 145 | flag.StringVar(&tokenFile, "tokens", "", "Token 文件路径") 146 | flag.StringVar(&tokenFile, "t", "", "Token 文件路径") 147 | flag.Parse() 148 | 149 | DEBUG = debug 150 | 151 | period := time.Now().AddDate(0, 0, 1).Format("2006-01-02") + " 21:00:00" 152 | 153 | tokens, err := read(tokenFile) 154 | if err != nil { 155 | fmt.Println(err) 156 | } 157 | 158 | fmt.Println(time.Now().Format("2006-01-02 15:04:05")) 159 | 160 | if submit { 161 | for _, token := range tokens { 162 | count := 100 163 | for count >= 0 { 164 | count-- 165 | 166 | status, id, info, err := Send(period, token) 167 | if status != 200 || id == "" { 168 | fmt.Printf("Status %d, ID %s Info %s\n%s\n", status, id, info, err) 169 | } else { 170 | fmt.Println(id, info) 171 | break 172 | } 173 | time.Sleep(time.Second * 1) 174 | } 175 | } 176 | } else { 177 | for _, token := range tokens { 178 | status, id, err := Keep(token) 179 | if id == "" { 180 | fmt.Printf("Status %d, ID %s\n%s\n", status, id, err) 181 | } else { 182 | fmt.Println(id, "ok") 183 | } 184 | } 185 | 186 | } 187 | fmt.Printf("Finished at %s\n\n\n", time.Now().Format("2006-01-02 15:04:05")) 188 | } 189 | -------------------------------------------------------------------------------- /bath/go/tokens.txt: -------------------------------------------------------------------------------- 1 | laravel_session=xxxxx -------------------------------------------------------------------------------- /bath/python/README.md: -------------------------------------------------------------------------------- 1 | # Python 语言版浴室预约脚本 2 | 3 | 运行参数: 4 | - `today` 预约今日的浴室 5 | - `tomorrow` 预约明日的浴室 6 | - 如果存在形如 `21:00:00` 的参数,则会预约对应时间的浴室(需要确保输入合法) 7 | - `laravel_session=` 要预约用户的 Token 数据 8 | - `debug` 调试模式 9 | -------------------------------------------------------------------------------- /bath/python/bath.py: -------------------------------------------------------------------------------- 1 | import re 2 | from time import sleep, time 3 | import requests 4 | import datetime 5 | import sys 6 | 7 | DEBUG = False 8 | 9 | 10 | def main(period, token): 11 | res = requests.post( 12 | "http://wx.bupt.edu.cn/bathroom/submit", 13 | data={ 14 | "period": period 15 | }, 16 | headers={ 17 | "user-agent": "MicroMessenger", 18 | }, 19 | cookies={ 20 | "laravel_session": token 21 | }, 22 | ) 23 | 24 | if DEBUG or res.status_code == 200: 25 | print(res.text) 26 | 27 | print(res.status_code, re.findall(r'
学工号: (\d+)
', res.text), 28 | re.findall(r'
(.*)
', res.text)) 29 | 30 | return res.status_code == 200 31 | 32 | 33 | if __name__ == "__main__": 34 | today = datetime.date.today() 35 | tomorrow = today+datetime.timedelta(days=1) 36 | at = today+datetime.timedelta(days=2) 37 | 38 | period = "21:00:00" 39 | token = "" 40 | 41 | rePeriod = r'^\d\d:\d\d:\d\d$' 42 | date = at 43 | for arg in sys.argv: 44 | if ("today" == arg): 45 | date = today 46 | if ("tomorrow" == arg): 47 | date = tomorrow 48 | if re.fullmatch(rePeriod, arg): 49 | period = arg 50 | if "laravel_session" in arg: 51 | token = arg.split("=")[1] 52 | if arg == "debug": 53 | DEBUG = True 54 | print("task:", date, period, "\n", token) 55 | 56 | while 1: 57 | if main("{} {}".format(date, period), token): 58 | break 59 | sleep(1) 60 | -------------------------------------------------------------------------------- /check/README.md: -------------------------------------------------------------------------------- 1 | # 疫情打卡脚本 2 | 3 | 自动在疫情防控通打卡 4 | 5 | 账号为学号 6 | 密码为服务门户密码(默认为身份证后8位) 7 | 8 | 账户和密码使用空格分割存放在`users.txt`中,一行一个用户 9 | 10 | 疫情打卡会使用前一天的数据结合当日需要修改的参数进行打卡,因此如果有部分项目需要修改,只需要有一天手动打卡即可,后续都会继续沿用前一日的数据 -------------------------------------------------------------------------------- /check/check.crontab.bash: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | #export PYTHONPATH="/usr/lib/python38.zip:/usr/lib/python3.8:/usr/lib/python3.8/lib-dynload:/home/ubuntu/.local/lib/python3.8/site-packages:/usr/local/lib/python3.8/dist-packages:/usr/lib/python3/dist-packages" 4 | 5 | SHELL_FOLDER=$(cd "$(dirname "$0")";pwd) 6 | 7 | date '+%Y-%m-%d %H:%M:%S' >> $SHELL_FOLDER/log.log 8 | python3 $SHELL_FOLDER/check.py 1>>$SHELL_FOLDER/log.log 2>>$SHELL_FOLDER/error.log -------------------------------------------------------------------------------- /check/check.py: -------------------------------------------------------------------------------- 1 | import requests 2 | import datetime 3 | import re 4 | import json 5 | import os 6 | import time 7 | import random 8 | 9 | 10 | oldKeys = [ 11 | "ismoved", "jhfjrq", "jhfjjtgj", "jhfjhbcc", "sfxk", "xkqq", "szgj", "szcs", "zgfxdq", "mjry", "csmjry", "uid", "tw", "sfcxtz", "sfyyjc", "jcjgqr", "jcjg", "sfjcbh", "sfcxzysx", "qksm", "remark", "address", "area", "province", "city", "geo_api_info", "sfzx", "sfjcwhry", "sfcyglq", "gllx", 12 | "glksrq", "jcbhlx", "jcbhrq", "sftjwh", "sftjhb", "fxyy", "bztcyy", "fjsj", "sfjchbry", "sfjcqz", "jcqzrq", "jcwhryfs", "jchbryfs", "xjzd", "sfsfbh", "jhfjsftjwh", "jhfjsftjhb", "szsqsfybl", "sfygtjzzfj", "gtjzzfjsj", "sfsqhzjkk", "sqhzjkkys", "created_uid", "gwszdd", "sfyqjzgc", "jrsfqzys", "jrsfqzfy" 13 | ] 14 | defaultKeys = [ 15 | "date", "created", "id", 16 | ] 17 | 18 | 19 | def login(session, username: str, password: str): 20 | resp = session.get("https://auth.bupt.edu.cn/authserver/login", data={ 21 | "username": username, 22 | "password": password, 23 | }) 24 | 25 | result =re.findall( r'', resp.text) 26 | if len(result) > 0: 27 | execution = result[0] 28 | else: 29 | execution = "" 30 | 31 | resp = session.post("https://auth.bupt.edu.cn/authserver/login", data={ 32 | "username": username, 33 | "password": password, 34 | "submit": "登录", 35 | "type": "username_password", 36 | "execution": execution, 37 | "_eventId": "submit", 38 | }) 39 | 40 | return True 41 | if resp.json()["e"] == 0: 42 | return True 43 | else: 44 | print(resp.text) 45 | return False 46 | 47 | def check(username: str, password: str): 48 | session = requests.Session() 49 | 50 | if login(session, username, password): 51 | print(username, "登录成功") 52 | else: 53 | print(username, "登录失败") 54 | return 55 | 56 | resp = session.get("https://app.bupt.edu.cn/ncov/wap/default/index") 57 | matchDefault = re.findall(r'var def = (.*);\n', resp.text) 58 | if (len(matchDefault) == 0): 59 | print("获取默认信息失败") 60 | return 61 | default = json.loads(matchDefault[0]) 62 | 63 | matchOld = re.findall(r'oldInfo: (.*),\n', resp.text) 64 | if (len(matchOld) == 0): 65 | print("获取上次信息失败") 66 | return 67 | oldInfo = json.loads(matchOld[0]) 68 | 69 | realnames = re.findall(r'realname: "(.*)",', resp.text) 70 | realname = "获取名称失败" 71 | if len(realnames) > 0: 72 | realname = realnames[0] 73 | 74 | data = {} 75 | for k in oldInfo: 76 | data[k] = oldInfo.get(k, "") 77 | for k in defaultKeys: 78 | data[k] = default.get(k, "") 79 | 80 | resp = session.post( 81 | "https://app.bupt.edu.cn/ncov/wap/default/save", data=data) 82 | 83 | j = resp.json() 84 | if j.get("e", 1) == 0: 85 | print(realname, "填报成功", oldInfo.get("address", "")) 86 | else: 87 | print(realname, "填报失败", j.get("m", "")) 88 | 89 | 90 | if __name__ == "__main__": 91 | random.seed(time.time()) 92 | with open(os.path.join(os.path.dirname(__file__), "users.txt")) as f: 93 | users = f.read().split("\n") 94 | random.shuffle(users) 95 | for u in users: 96 | sleepTime = random.randint(10,30) 97 | time.sleep(sleepTime) 98 | try: 99 | if u != "": 100 | username, password = u.split(" ") 101 | print(username+' sleep time:'+str(sleepTime)) 102 | check(username, password) 103 | except Exception as e: 104 | print(e) 105 | -------------------------------------------------------------------------------- /check/users.txt: -------------------------------------------------------------------------------- 1 | 2019111111 11111111 2 | 2019111112 11111112 3 | -------------------------------------------------------------------------------- /crontab.bash: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 运行该文件将相关定时任务追加至 crontab 中 3 | 4 | SHELL_FOLDER=$(cd "$(dirname "$0")";pwd) 5 | 6 | crontab -l > ./crontab.temp 7 | echo " 8 | # bupt 9 | 30 0 * * * /bin/bash $SHELL_FOLDER/check/check.crontab.bash 10 | 30 6 * * * /bin/bash $SHELL_FOLDER/check/check.crontab.bash 11 | 0 7 * * * /bin/bash $SHELL_FOLDER/leave/leave.crontab.bash 12 | " >> ./crontab.temp 13 | crontab ./crontab.temp 14 | rm crontab.temp 15 | 16 | crontab -l -------------------------------------------------------------------------------- /leave/README.md: -------------------------------------------------------------------------------- 1 | # 自动请假脚本 2 | 3 | 在`users.txt`中以 yaml 格式填入数据,每个用户包含以下字段 4 | - username: 用户名 5 | - password: 服务门户密码(默认身份证后 8 位) 6 | - phone: 手机号 7 | - position: 要去的地方(不填写默认实验室) 8 | - reason: 出校原因(不填写默认科研) 9 | - school: 校区(不填写默认西土城) 10 | - teacher_uid: 辅导员 id(需要自己在相应页面按 F12 查看,虽然有查询接口,但是有重名概率) 11 | - teacher_name: 辅导员姓名 12 | 13 | 每两个用户使用单独的一行`---`分割 14 | 15 | ``` 16 | username: "2019111111" 17 | password: "11111111" 18 | phone: "19999999999" 19 | position: "实验室" 20 | reason: "科研" 21 | school: "西土城" 22 | teacher_uid: 000 23 | teacher_name: "xxx" 24 | ``` -------------------------------------------------------------------------------- /leave/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 请假外出、返校权限查询通行码 8 | 182 | 183 | 184 | 185 |
网页由 service.bupt.edu.cn 提供
186 |
187 | 188 |
请假外出、返校权限查询 190 |
191 |
姓名
192 |
川建国
193 |
学院
194 |
计算机学院(国家示范性软件学院)
195 |
状态码
196 |
198 |
199 |
状态
200 |
允许入校
201 |
学工号
202 |
2019123321
203 |
出入校时间
204 |
2020-09-07 00:00:00
205 |
206 |
207 | 208 |
209 | 210 |
211 | 212 | 216 | 217 | 244 | 245 | 347 | 348 | 349 | 350 | -------------------------------------------------------------------------------- /leave/leave.crontab.bash: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | #export PYTHONPATH="/usr/lib/python38.zip:/usr/lib/python3.8:/usr/lib/python3.8/lib-dynload:/home/ubuntu/.local/lib/python3.8/site-packages:/usr/local/lib/python3.8/dist-packages:/usr/lib/python3/dist-packages" 4 | SHELL_FOLDER=$(cd "$(dirname "$0")";pwd) 5 | 6 | date '+%Y-%m-%d %H:%M:%S' >> $SHELL_FOLDER/log.log 7 | python3 $SHELL_FOLDER/leave.py 1>>$SHELL_FOLDER/log.log 2>>$SHELL_FOLDER/error.log -------------------------------------------------------------------------------- /leave/leave.py: -------------------------------------------------------------------------------- 1 | import json 2 | from urllib import parse 3 | import requests 4 | import datetime 5 | import re 6 | import yaml 7 | import os 8 | 9 | session = requests.Session() 10 | schools = { 11 | "沙河": {"name": "沙河校区", "value": "1", "default": 0, "imgdata": ""}, 12 | "西土城": {"name": "西土城校区", "value": "2", "default": 0, "imgdata": ""}, 13 | } 14 | 15 | 16 | def login(username: str, password: str): 17 | session.cookies.clear() 18 | resp = session.get("https://auth.bupt.edu.cn/authserver/login") 19 | matchLT = re.findall( 20 | r'', resp.text) 21 | if len(matchLT) == 0: 22 | print("登录 CSRF 加载错误") 23 | return "" 24 | lt = matchLT[0] 25 | 26 | resp = session.post( 27 | "https://auth.bupt.edu.cn/authserver/login?service=https%3A%2F%2Fme.bupt.edu.cn%2Fsite%2Flogin%2Fcas-login", 28 | data={ 29 | "username": username, 30 | "password": password, 31 | "lt": lt, 32 | "execution": "e1s1", 33 | "_eventId": "submit", 34 | "rmShown": 1, 35 | }) 36 | 37 | matchUserInfo = re.findall( 38 | r'
\s*\s*([^\s]*)\s*\s*', 39 | resp.text 40 | ) 41 | if len(matchUserInfo) != 0: 42 | return matchUserInfo[0] 43 | return "" 44 | 45 | 46 | def getCollege(): 47 | resp = session.get("https://service.bupt.edu.cn/site/user/get-name") 48 | return resp.json()["d"]["college"] 49 | 50 | 51 | def leave( 52 | username: str, 53 | password: str, 54 | phone: str, 55 | position: str, 56 | reason: str, 57 | school: object, 58 | teacher: object 59 | ): 60 | name = login(username, password) 61 | if name == "": 62 | print(username, "登录失败") 63 | return 64 | print(name, "登录成功") 65 | 66 | college = getCollege() 67 | 68 | tomorrow = datetime.datetime.now() + datetime.timedelta(days=1) 69 | 70 | date = tomorrow.replace( 71 | hour=0, minute=0, second=0, 72 | microsecond=0 73 | ).isoformat(timespec="microseconds")[:-7] + "+08:00" 74 | 75 | beginTime = tomorrow.replace( 76 | hour=7, minute=0, second=0, microsecond=0 77 | ).astimezone( 78 | tz=datetime.timezone.utc 79 | ).isoformat(timespec="microseconds").replace("000+00:00", "Z") 80 | endTime = tomorrow.replace( 81 | hour=23, minute=59, second=59, microsecond=0 82 | ).astimezone( 83 | tz=datetime.timezone.utc 84 | ).isoformat(timespec="microseconds").replace("000+00:00", "Z") 85 | 86 | 87 | 88 | data = { 89 | "data": { 90 | "app_id": "578", 91 | "node_id": "", 92 | "form_data": { 93 | "1716": { 94 | "Alert_67": "", 95 | "Count_74": {"type": 0, "value": 1}, # unused 96 | "Valudate_66": "", # unused 97 | "User_5": name, 98 | "User_7": username, 99 | "User_9": college, 100 | "User_11": phone, 101 | "Input_28": position, 102 | "Radio_52": { 103 | "value": "1", 104 | "name": "本人已阅读并承诺", 105 | }, 106 | "Radio_73": { 107 | "value": "1", 108 | "name": "是", 109 | }, 110 | "Calendar_47": endTime, 111 | "Calendar_50": beginTime, 112 | "Calendar_62": date, 113 | "Calendar_69": date, # unused 114 | "SelectV2_58": [schools[school]], 115 | "MultiInput_30": reason, 116 | "UserSearch_60": teacher, 117 | "UserSearch_73": teacher, # unused 118 | "Validate_63": "", 119 | "Alert_65": "", 120 | "Validate_66": "", 121 | "Variate_74": "否", # unused 122 | "DataSource_75": "" # unused 123 | } 124 | }, 125 | "userview": 1, 126 | "special_approver": [ 127 | { 128 | "node_key": "UserTask_100lwr4", 129 | "uids": [ 130 | teacher.get("uid", "") 131 | ], 132 | "subprocessIndex": "" 133 | } 134 | ] 135 | } 136 | } 137 | 138 | resp = session.post( 139 | "https://service.bupt.edu.cn/site/apps/launch", 140 | data="data=" + parse.quote(str(data["data"]).replace( 141 | "'", '"').replace(" ", "")), 142 | headers={ 143 | "Content-Type": "application/x-www-form-urlencoded", 144 | "UserAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.75 Safari/537.36 Edg/86.0.622.38", 145 | # "refer": "https://service.bupt.edu.cn/v2/matter/start?id=578", 146 | "x-requested-with": "XMLHttpRequest", 147 | # "accept": "application/json, text/plain, */*", 148 | } 149 | ) 150 | resp.encoding = "utf-8" 151 | print(resp.text) 152 | 153 | 154 | if __name__ == "__main__": 155 | with open(os.path.join(os.path.dirname(__file__), "users.txt")) as f: 156 | users = yaml.load_all(f, Loader=yaml.FullLoader) 157 | for u in users: 158 | try: 159 | leave( 160 | username=u["username"], 161 | password=u["password"], 162 | phone=u["phone"], 163 | position=u.get("position", "实验室"), 164 | reason=u.get("reason", "科研"), 165 | school=u.get("school", "西土城"), 166 | teacher={ 167 | "uid": u.get("teacher_uid", 0), 168 | "name": u.get("teacher_name", ""), 169 | "number": u.get("teacher_number", "") 170 | } 171 | ) 172 | except Exception as e: 173 | print(e.print_exc()) 174 | -------------------------------------------------------------------------------- /leave/users.txt: -------------------------------------------------------------------------------- 1 | username: "2019111111" 2 | password: "11111111" 3 | phone: "19999999999" 4 | position: "实验室" 5 | reason: "科研" 6 | school: "西土城" 7 | teacher_uid: 000 8 | teacher_name: "xxx" 9 | teacher_number: "1234" 10 | --- 11 | username: "2019111111" 12 | password: "11111111" 13 | phone: "19999999999" 14 | position: "实验室" 15 | reason: "科研" 16 | school: "西土城" 17 | teacher_uid: 000 18 | teacher_name: "xxx" 19 | teacher_number: "1234" -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | requests --------------------------------------------------------------------------------