mirror of
https://github.com/lifegpc/pythonscript.git
synced 2026-06-06 11:28:58 +08:00
398 lines
15 KiB
Python
398 lines
15 KiB
Python
from argparse import ArgumentParser
|
|
from getpass import getpass
|
|
from hashlib import sha1 as _sha1
|
|
from json import dumps as _dumps, load
|
|
from math import ceil
|
|
from random import random
|
|
from urllib.parse import urlencode
|
|
from requests import Session
|
|
|
|
|
|
def stringify(json):
|
|
return _dumps(json, ensure_ascii=False, separators=(",", ":"))
|
|
|
|
|
|
def sha1(data: str):
|
|
f = _sha1()
|
|
f.update(data.encode())
|
|
return f.hexdigest()
|
|
|
|
|
|
class Client():
|
|
MYSHOP_FORAPP_KEY = "987654321"
|
|
SOFTWARE = "0"
|
|
LOGINDEVICETYPE = "android"
|
|
FROMANDROID = "1"
|
|
VERSION = "131"
|
|
DEVICEID = "设备Id获取失败,null值!版本\u003d131"
|
|
|
|
def __init__(self):
|
|
self._ses = Session()
|
|
self._ses.headers.update({
|
|
"User-Agent": "okhttp/3.6.0",
|
|
"Accept-Encoding": "gzip",
|
|
})
|
|
self._baseUrl = "http://39.104.60.22:6023/"
|
|
self._token = ""
|
|
self._fromteacher = False
|
|
self._portalUrl = None
|
|
|
|
def check_in(self, longitude: float, latitude: float, localname, note):
|
|
if self._portalUrl is None:
|
|
raise Exception("请先选择医院")
|
|
if not self._token:
|
|
raise Exception("请先登录")
|
|
url = self._portalUrl + "doctor_train/rest/ningboschedule/signstudent.do" # noqa: E501
|
|
url += f"?{self.get_base_params()}"
|
|
d = stringify({
|
|
"logindevicetype": self.LOGINDEVICETYPE,
|
|
"longitude": f"{longitude:.06f}",
|
|
"latitude": f"{latitude:.06f}",
|
|
"fromandroid": self.FROMANDROID,
|
|
"note": note,
|
|
"fromteacher": "1" if self._fromteacher else "0",
|
|
"localname": localname,
|
|
})
|
|
re = self._ses.post(url, data={"data": d})
|
|
if re.status_code != 200:
|
|
raise Exception(f"HTTP {re.status_code} {re.reason}")
|
|
return self.check_error2(re.json())
|
|
|
|
def check_error(self, r):
|
|
if r["code"] != "1" or "data" not in r or r["data"] is None:
|
|
raise Exception(f"Error: {r['msg']}")
|
|
return r["data"]
|
|
|
|
def check_error2(self, r):
|
|
if r["code"] != "1":
|
|
raise Exception(f"Error: {r['msg']}")
|
|
return r
|
|
|
|
def get_base_params(self):
|
|
d = {
|
|
"token": self._token,
|
|
"myshop_app_key": self.MYSHOP_FORAPP_KEY,
|
|
"software": self.SOFTWARE,
|
|
}
|
|
return urlencode(d)
|
|
|
|
def get_ningbo_schedule_init_data(self):
|
|
if self._portalUrl is None:
|
|
raise Exception("请先选择医院")
|
|
if not self._token:
|
|
raise Exception("请先登录")
|
|
url = self._portalUrl + "doctor_train/rest/ningboschedule/getInitData.do" # noqa: E501
|
|
url += f"?{self.get_base_params()}"
|
|
d = stringify({
|
|
"logindevicetype": self.LOGINDEVICETYPE,
|
|
"fromteacher": "1" if self._fromteacher else "0",
|
|
"fromandroid": self.FROMANDROID,
|
|
})
|
|
re = self._ses.post(url, data={"data": d})
|
|
if re.status_code != 200:
|
|
raise Exception(f"HTTP {re.status_code} {re.reason}")
|
|
return self.check_error2(re.json())
|
|
|
|
def login_check(self, loginid: str, password: str):
|
|
if self._portalUrl is None:
|
|
raise Exception("请先选择医院")
|
|
url = self._portalUrl + "doctor_portal/rest/loginCheck.do"
|
|
url += f"?{self.get_base_params()}"
|
|
d = stringify({
|
|
"logindevicetype": self.LOGINDEVICETYPE,
|
|
"password": sha1(password),
|
|
"fromandroid": self.FROMANDROID,
|
|
"devicetype": self.LOGINDEVICETYPE,
|
|
"deviceid": self.DEVICEID,
|
|
"fromteacher": "1" if self._fromteacher else "0",
|
|
"loginid": loginid,
|
|
"mac": self.DEVICEID,
|
|
})
|
|
re = self._ses.post(url, data={"data": d})
|
|
if re.status_code != 200:
|
|
raise Exception(f"HTTP {re.status_code} {re.reason}")
|
|
return self.check_error2(re.json())
|
|
|
|
def init_with_hospital(self, hospital):
|
|
self._portalUrl = f'http://{hospital["portalurl"]}/'
|
|
|
|
def init_with_user(self, user):
|
|
self._token = user["token"]
|
|
|
|
def query_train_hospital(self):
|
|
url = self._baseUrl + "cloud_doctor_train/rest/trainHospital/query.do"
|
|
url += f"?{self.get_base_params()}"
|
|
d = stringify({
|
|
"logindevicetype": self.LOGINDEVICETYPE,
|
|
"fromteacher": "1" if self._fromteacher else "0",
|
|
"fromandroid": self.FROMANDROID,
|
|
})
|
|
re = self._ses.post(url, data={"data": d})
|
|
if re.status_code != 200:
|
|
raise Exception(f"HTTP {re.status_code} {re.reason}")
|
|
return self.check_error(re.json())
|
|
|
|
|
|
class Main():
|
|
def __init__(self, config, arg):
|
|
self._config = config
|
|
self._arg = arg
|
|
self._client = Client()
|
|
|
|
def ask_choice(self, choices: list, prompt="请选择:", fn=None, extra=None):
|
|
count = len(choices)
|
|
total_pages = ceil(count / self._arg.page_size)
|
|
page = 1
|
|
|
|
def show_page():
|
|
nonlocal page
|
|
base = (page - 1) * self._arg.page_size
|
|
if total_pages > 1:
|
|
print(f"第{page}/{total_pages}页")
|
|
for i in range(self._arg.page_size):
|
|
index = base + i
|
|
if index >= count:
|
|
break
|
|
s = fn(choices[index]) if fn else choices[index]
|
|
print(f"{i}. {s}")
|
|
if page > 1:
|
|
print("f. 第一页")
|
|
print("p. 上一页")
|
|
if page < total_pages:
|
|
print("n. 下一页")
|
|
print("l. 最后一页")
|
|
if extra is not None:
|
|
for t in extra:
|
|
print(f"{t[0]}. {t[1]}")
|
|
|
|
while True:
|
|
show_page()
|
|
s = input(prompt)
|
|
if s == "f":
|
|
page = 1
|
|
elif s == "p":
|
|
page = max(1, page - 1)
|
|
elif s == "n":
|
|
page = min(total_pages, page + 1)
|
|
elif s == "l":
|
|
page = total_pages
|
|
else:
|
|
if extra is not None:
|
|
for t in extra:
|
|
if t[0] == s:
|
|
return t[2]
|
|
try:
|
|
index = int(s)
|
|
except Exception:
|
|
continue
|
|
base = (page - 1) * self._arg.page_size
|
|
index += base
|
|
if index < 0 or index >= count:
|
|
continue
|
|
return choices[index]
|
|
|
|
def checkIn(self):
|
|
self.init_client()
|
|
if "location" not in self._config:
|
|
self._config["location"] = []
|
|
location = self.ask_choice(self._config["location"], "请选择位置:", lambda x: f'{x["name"]} ({x["longitude"]},{x["latitude"]},{x["localname"]})', [("a", "添加位置", "add")]) # noqa: E501
|
|
if location == "add":
|
|
name = input("请输入位置名称(仅用作标识,不会上传到服务器):")
|
|
longitude = float(input("请输入经度:"))
|
|
latitude = float(input("请输入纬度:"))
|
|
localname = input("请输入地名(会在签到时上传到服务器):")
|
|
location = {
|
|
"name": name,
|
|
"longitude": longitude,
|
|
"latitude": latitude,
|
|
"localname": localname,
|
|
"longitude_radius": 0.00001,
|
|
"latitude_radius": 0.00001,
|
|
}
|
|
while True:
|
|
self.show_location(location)
|
|
s = input("是否需要进行调整?(y/n)")
|
|
if s == "n":
|
|
break
|
|
elif s == "y":
|
|
t = {
|
|
"name": "位置名称",
|
|
"longitude": "经度",
|
|
"latitude": "纬度",
|
|
"localname": "地名",
|
|
"longitude_radius": "随机化经度半径",
|
|
"latitude_radius": "随机化纬度半径",
|
|
}
|
|
c = self.ask_choice(["name", "longitude", "latitude",
|
|
"localname", "longitude_radius",
|
|
"latitude_radius"], "请选择要修改的内容:",
|
|
lambda x: t[x])
|
|
if c == "name":
|
|
location["name"] = input("请输入位置名称:")
|
|
elif c == "longitude":
|
|
location["longitude"] = float(input("请输入经度:"))
|
|
elif c == "latitude":
|
|
location["latitude"] = float(input("请输入纬度:"))
|
|
elif c == "localname":
|
|
location["localname"] = input("请输入地名:")
|
|
elif c == "longitude_radius":
|
|
location["longitude_radius"] = float(
|
|
input("请输入随机化经度半径:"))
|
|
elif c == "latitude_radius":
|
|
location["latitude_radius"] = float(
|
|
input("请输入随机化纬度半径:"))
|
|
else:
|
|
continue
|
|
self._config["location"].append(location)
|
|
print("获取签到信息...")
|
|
data = self._client.get_ningbo_schedule_init_data()
|
|
print("已签到列表:")
|
|
for x in data["signlist"]:
|
|
print(x)
|
|
prompt = f"要进行{data['buttonname']}吗?(y/n)"
|
|
while True:
|
|
s = input(prompt)
|
|
if s == "y":
|
|
break
|
|
elif s == "n":
|
|
return
|
|
localname = location["localname"]
|
|
longitude = round(location["longitude"] + (random() - 0.5) * location["longitude_radius"], 6) # noqa: E501
|
|
latitude = round(location["latitude"] + (random() - 0.5) * location["latitude_radius"], 6) # noqa: E501
|
|
note = ""
|
|
if self._arg.note:
|
|
note = self._arg.note
|
|
while True:
|
|
print("经度:", longitude)
|
|
print("纬度:", latitude)
|
|
print("地名:", localname)
|
|
print("备注:", note)
|
|
s = input("是否需要进行调整?(y/n)")
|
|
if s == "n":
|
|
break
|
|
elif s == "y":
|
|
t = {
|
|
"longitude": "经度",
|
|
"latitude": "纬度",
|
|
"localname": "地名",
|
|
"note": "备注",
|
|
}
|
|
c = self.ask_choice(["longitude", "latitude", "localname",
|
|
"note"], "请选择要修改的内容:", lambda x: t[x])
|
|
if c == "longitude":
|
|
longitude = float(input("请输入经度:"))
|
|
elif c == "latitude":
|
|
latitude = float(input("请输入纬度:"))
|
|
elif c == "localname":
|
|
localname = input("请输入地名:")
|
|
elif c == "note":
|
|
note = input("请输入备注:")
|
|
print("签到中...")
|
|
self._client.check_in(longitude, latitude, localname, note)
|
|
print("签到成功")
|
|
|
|
def get_hospital(self):
|
|
print("获取医院列表...")
|
|
data = self._client.query_train_hospital()
|
|
if self._arg.hospital_id:
|
|
for x in data:
|
|
if x["trainhospitalid"] == self._arg.hospital_id:
|
|
return x
|
|
raise Exception(f"医院ID {self._arg.hospital_id} 不存在")
|
|
if self._arg.hospital_name:
|
|
for x in data:
|
|
if x["name"] == self._arg.hospital_name:
|
|
return x
|
|
raise Exception(f"医院名称 {self._arg.hospital_name} 不存在")
|
|
if self._arg.hospital_code:
|
|
for x in data:
|
|
if x["hospitalcode"] == self._arg.hospital_code:
|
|
return x
|
|
raise Exception(f"医院编码 {self._arg.hospital_code} 不存在")
|
|
return self.ask_choice(data, "请选择医院:", lambda x: x["name"])
|
|
|
|
def init_client(self):
|
|
if "hospital" not in self._config or "user" not in self._config:
|
|
self.login()
|
|
else:
|
|
self._client.init_with_hospital(self._config["hospital"])
|
|
self._client.init_with_user(self._config["user"])
|
|
|
|
def login(self):
|
|
if "hospital" not in self._config or self._arg.change_hospital:
|
|
self._config["hospital"] = self.get_hospital()
|
|
self._client.init_with_hospital(self._config["hospital"])
|
|
if self._arg.login_id is None:
|
|
self._arg.login_id = input("请输入登录ID:")
|
|
if self._arg.password is None:
|
|
if self._arg.no_getpass:
|
|
self._arg.password = input("请输入密码:")
|
|
else:
|
|
self._arg.password = getpass("请输入密码:")
|
|
print("登录中...")
|
|
self._config["user"] = self._client.login_check(
|
|
self._arg.login_id, self._arg.password)
|
|
self._client.init_with_user(self._config["user"])
|
|
print("登录成功")
|
|
|
|
def show_location(self, loc):
|
|
print("位置名称:", loc["name"])
|
|
print("经度:", loc["longitude"])
|
|
print("纬度:", loc["latitude"])
|
|
print("地名:", loc["localname"])
|
|
print("随机化经度半径:", loc["longitude_radius"])
|
|
print("随机化纬度半径:", loc["latitude_radius"])
|
|
|
|
|
|
ACTIONS = ["login", "checkin"]
|
|
EACTIONS = ["login2"]
|
|
|
|
|
|
def get_action_str(action):
|
|
if action == "login":
|
|
return "登录"
|
|
elif action == "login2":
|
|
return "登录(重新选择医院)"
|
|
elif action == "checkin":
|
|
return "签到"
|
|
|
|
|
|
def main(args=None):
|
|
p = ArgumentParser()
|
|
p.add_argument("-c", "--config", default="zyys.json", help="配置文件")
|
|
p.add_argument("-l", "--login-id", help="登录ID")
|
|
p.add_argument("-p", "--password", help="密码")
|
|
p.add_argument("--hospital-id", help="医院ID", type=int)
|
|
p.add_argument("--hospital-name", help="医院名称")
|
|
p.add_argument("--hospital-code", help="医院编码")
|
|
p.add_argument("-P", "--page-size", default=10, help="每页数量", type=int)
|
|
p.add_argument("-C", "--change-hospital", action="store_true",
|
|
help="重新选择医院")
|
|
p.add_argument("--no-getpass", action="store_true", help="不使用getpass")
|
|
p.add_argument("-n", "--note", help="备注")
|
|
p.add_argument("action", choices=ACTIONS, help="操作", nargs="?")
|
|
arg = p.parse_args(args)
|
|
try:
|
|
with open(arg.config) as f:
|
|
config = load(f)
|
|
except Exception:
|
|
config = {}
|
|
m = Main(config, arg)
|
|
if arg.action is None:
|
|
arg.action = m.ask_choice(ACTIONS + EACTIONS, "请选择操作:", get_action_str)
|
|
try:
|
|
if arg.action == "login":
|
|
m.login()
|
|
elif arg.action == "login2":
|
|
arg.change_hospital = True
|
|
m.login()
|
|
elif arg.action == "checkin":
|
|
m.checkIn()
|
|
finally:
|
|
with open(arg.config, "w") as f:
|
|
f.write(stringify(config))
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|