Python 实现医院定时自动挂号和快捷查询化验报告

为什么要做这个事情

去年单位体检查出来点问题,经过穿刺手术确诊是个慢性肾脏病2期, IGA 肾病三期,可能大家对于这个病并不是很了解,在此之前我也没听说过,但是另外一个词可能大家都听过,叫”尿毒症”。

什么是慢性肾脏病

慢性肾脏病分五期,终末期就是尿毒症。慢性肾脏病非常隐秘,并且病情进展缓慢,一般如果不科学的控制到尿毒症需要0-20年时间,如果不是体检化验尿液看里面的隐血和尿蛋白指标,根本没任何感觉。你有时候会感觉腰疼,但是腰疼其实跟肾脏病没啥关系。所以大家一定要定期体检。

慢性肾脏病CKD分期 eGRR值 相当于正常肾功能的程度(%)
1期 ≥90 100%
2期 轻度异常 60-89 50-100%
3期 中度异常 30-59 30-50%
4期 重度异常 15-29 10-30%
5期 肾功能衰竭 0-14 <10%
慢性肾脏病CKD分期 临床症状 建议
1期 可能有泡沫尿、血尿、 血压上升 、眼睑及双下肢浮肿、腰痛 及早到肾内科就诊, 改善生活方式
2期 轻度异常 饮食治疗,必要时药物治疗
3期 中度异常 可能有尿量的变化尤其是夜尿增多,血压上升,贫血 药物治疗, 继续饮食治疗
4期 重度异常 易疲劳,出现浮肿,前述症状加重
5期 肾功能衰竭 血压升高明显,浮肿加重,食欲下降,恶心,胸闷,尿量减少,皮肤瘙痒等 透析疗法,(腹膜透析、血液透析) 肾移植

需要说明的是 肾脏病和”肾虚”不是一个概念,”肾虚”是中医里面的说法,而且中医里面的肾他并不是指具体的肾脏这个器官,而是整个人的一个精神状态。中医嘛,大病治不好,但是中医最喜欢说我们中医是从全方位来调理你的身体。而西医里面的肾脏病就是指你的肾脏,俗称”腰子”,人体的肾脏是用来排毒的,人每天吃进去的东西经过消化会有一些残余的毒素是要通过肾脏代谢然后以尿液的形式排出。一般衡量这个这个指标是通过血肌酐来判断,血肌酐值越高说明你的身体毒素越多。

如果肾脏出现问题,肾小球过滤能力 eGRR 就会变小,如上面的表格所示,那么排毒功能就会受损,血肌酐值就会快速上升,并且肾脏一旦遭受损失是不可逆的。肾小球无法自我修复,那么当肾脏受损越来越严重,人体的残留的毒素就会越来越多的堆积在体内,就会出现各种并发症。比如高血压,贫血、电解质紊乱,各种指标超标例如磷、钾等等超标。

当肾小球过滤能力越来越差,肾脏过滤能力就会一步一步恶直到肾脏失去作用,就叫”尿毒症”,当得了”尿毒症”,就必须通过肾脏移植或透析(血液透析或腹膜透析)来代替肾脏的排毒功能将体内的毒素排出。肾脏移植费用昂贵,且非常稀缺,并且还需要配型成功才可以。想要同时满足这3个条件并不容易,有的人可能排队很久都没有适合自己的肾源,肾脏移植并不是说随随便便一个人的肾脏都可以用的,人体会对外来器官有排斥的。大多数人都是通过血液透析或腹膜透析来对体内的毒素进行排除,血液透析就是通过设备将体内的血液进行清洗,将毒素排除然后将干净的血液送回体内。这个在终末期肾病时一周需要做3次。腹膜透析也是通过一种医学液体将体内的毒素排出。

什么是 IGA

那么什么是 IGA 肾病呢? IGA 肾病是一种免疫系统异常导致正常的免疫系统攻击了肾脏的肾小球,把肾小球给破坏了。然后导致肾脏一步一步恶化。人发烧感冒流鼻涕咳嗽都是人体的免疫系统工作的一种反应,用来对抗外来入侵者,IGA 可以理解为就是免疫系统认错了对象,把正常的细胞当成了入侵者进行攻击。具体这个病可以参考IgA肾病的治疗与预后

在得知自己得了这个病之后那一段时间心态是奔溃的,这么年纪轻轻的怎么会得这种病呢?

其实,肾脏病的发病根源是无法追溯的,可能你吃了有肾毒性的中药或西药或食品,比如关木通、雷公藤等等,或者是一次不起眼的感冒发烧或者一次炎症感染或牙龈肿痛等等以及日常饮食不规范,每天喝水喝少了、憋尿都有可能导致肾脏损伤。 所以大家有点小毛病一定要及时去正规医院出来。尤其是小感冒觉得无所谓,我在此之前体检一直都正常,就前年冬天咳嗽2周。我都怀疑是不是那次引起的。另外此前还喜欢喝饮料,比如可乐,中午没精神来杯八二年的可乐压压惊,后来看报道说有个小伙把饮料当日常的水喝,结果得了尿毒症,吓得我赶紧把所有饮料都戒了。

慢性病有很多,比如高血压、糖尿病等等,肾病只是其中一种,这种病需要长期治疗和科学的管理,包括药物控制和饮食控制,比如通过激素或免疫抑制剂 一些降压药控制血压来达到降低尿蛋白等手段以及日常饮食限蛋白限盐,防止感冒等,适量食用优质蛋白等。以目前的医学这个病是治不好的,只能控制病情不继续发展下去,目前看我的结果还不算特别严重,肾小球过滤能力还和正常人差不多,但是如果控制不好,可能就越来越严重了。据说全国10几亿人每10个人就有一个人得这种慢性病,所以这大半年基本每个月都得往医院跑几次。

医院挂号有啥问题

说了这么多关于我的病情,就知道我以后肯定是老往医院跑了。那么大家都知道三甲医院那个人满为患,挂号什么的排队跟春运买火车票一样的。不过好在现在一些医院也提供了在线预约挂号的功能了,但是这个功能他不完美,为啥呢? 首先,医院一般放号都是只提前放一周的。而且放号时间是固定的比如下午三点,那这样就带来2个问题:

第一,我必须得算好了他们的医生上班时间。
第二,我必须掐着点去他们的 APP 挂号。

但是我不想守着点去他们的APP 去挂号。

我希望在指定时间去挂号,比如每个月的第一个周三去预约下周三的指定专家的号,最好嘛还是抢到最先的号,早看完早结束,早点8点去看,看完还不耽误上班。

实现自动挂号代码

于是就自己通过 Charles 抓包分析了医院的 APP 的请求,这里是分析浙江大学第一附属医院的 APP,然后用 Python 写了个脚本去模拟登录医院的 APP 然后去挂号,具体代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
import requests
import json
import time
import datetime
from dateutil.relativedelta import relativedelta

# 登录获取session_id
def login(username,password):

url = "https://zyyy.zwjk.com/api/exec.htm"
data = {"api_Channel":"1",
"client_version":"3.6.6",
"app_id":"zyyy_android",
"app_key":"xxxx",
"user_type":"0",
"client_mobile":"863008041030718",
"api_name":"api.user.user.login.info",
"params":{"phone":username, # 账号
"psw":password}, # 密码
}
headers = {
'Content-Type': "application/x-www-form-urlencoded",
'User-Agent': "health",
'Host': "zyyy.zwjk.com",
'Connection': "Keep-Alive",
'Accept': "application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5",
'cache-control': "no-cache",
}

response = requests_session.post( url, data={"requestData":json.dumps(data)}, headers=headers)

if response.status_code != 200:
return False
resp_json = response.json()
session_id = resp_json['return_params']['user_model']['session_id']
return session_id


# 获取挂号信息

def get_doctor_info(session_id,appointment_date):

url = "https://zyyy.zwjk.com/api/exec.htm"
payload = {"api_Channel":"1",
"client_version":"3.6.6",
"app_id":"zyyy_android",
"app_key":"xxxx",
"user_type":"0",
"client_mobile":"863008041030718",
"api_name":"api.yygh.expert.schedule.list",
"params":{"type_id":1,
"source_id":"12",
"dept_id":26,
"page_no":1,
"page_size":2147483647
},
"session_id":session_id}

headers = {
'Content-Type': "application/x-www-form-urlencoded",
'User-Agent': "health",
'Host': "zyyy.zwjk.com",
'Connection': "Keep-Alive",
'Accept': "application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5",
'cache-control': "no-cache",
}

response = requests_session.post(url, data={"requestData":json.dumps(payload)}, headers=headers)

if response.status_code != 200:
return False
resp_json = response.json()
return_params = resp_json['return_params']['list']

for key in return_params:
if int(key['date']) == int(appointment_date):
doctor_info = key['doctor']
for i in doctor_info:
if i['id'] == 1960 and i['schedulList'][0]['am_pm_flag'] == "1":
return True

def get_time(session_id):
pre_date = (time_now + datetime.timedelta(days=7)).strftime("%Y-%m-%d")

url = "https://zyyy.zwjk.com/api/exec.htm"
payload = {
"api_Channel": "1",
"client_version": "3.6.6",
"app_id": "zyyy_android",
"app_key": "xxxx",
"user_type": "0",
"client_mobile": "863008041030718",
"api_name": "api.yygh.remain.num",
"params": {
"sourceId": "12",
"planId": 9759,
"orderDate": str(pre_date),
"ampmFlag": "1"
},
"session_id": session_id
}


headers = {
'Content-Type': "application/x-www-form-urlencoded",
'User-Agent': "health",
'Host': "zyyy.zwjk.com",
'Connection': "Keep-Alive",
'Accept': "application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5",
'cache-control': "no-cache",
}

response = requests_session.post(url, data={"requestData": json.dumps(payload)}, headers=headers)

if response.status_code != 200:
return False
resp_json = response.json()
regno = resp_json['return_params']['list'][0]['regno']
timespan = resp_json['return_params']['list'][0]['timespan']
return [regno,timespan]


# 在指定时间挂号

def set_doctor_number(session_id,pre_date,reg_no,timeregion):
url = "https://zyyy.zwjk.com/api/exec.htm"
payload = {
"api_Channel": "1",
"client_version": "3.6.6",
"app_id": "zyyy_android",
"app_key": "Zxxxx",
"user_type": "0",
"client_mobile": "863008041030718",
"api_name": "api.yygh.expert.reservation",
"params": {
"card_no": "x'x'x'x", # 社保卡号
"doct_name": "华佗", # 专家名称
"user_name": "xxx", # 你的姓名
"id_card": "xxxxx", # 身份证号
"phone": "xxxx", # 电话
"reg_id": "xxxx",
"reg_no": reg_no, # 预约号
"dept_name": "科室",
"yuanqu_type": "1",
"type": "1",
"dept_id": 103060302,
"pre_date": str(pre_date), #预约日期
"week_day": "3", # 预约日期是星期几
"plan_id": 9759,
"fee": "14",
"pre_time_type": "1",
"doct_id": "1960",
"clinic_fee": "",
"clinic_time":timeregion
},
"session_id": str(session_id)
}

headers = {
'Content-Type': "application/x-www-form-urlencoded",
'User-Agent': "health",
'Host': "zyyy.zwjk.com",
'Connection': "Keep-Alive",
'Accept': "application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5",
'cache-control': "no-cache",
}

response = requests_session.post(url, data={"requestData": json.dumps(payload)}, headers=headers)

if response.status_code != 200:
return False
resp_json = response.json()
ret_info = resp_json['return_params']['ret_info']
send_message_wchat("浙一预约挂号结果",ret_info)

# 发送消息到微信
def send_message_wchat(title, content):
loging_datetime = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
url = "https://sc.ftqq.com/SCU9051Tc94a746xxxf1d559xxx5a545ff.send"
querystring = {"text": title, "desp": str(loging_datetime) + str(content)}
response = requests.request("GET", url, params=querystring)
if response != 200:
return
return True


if __name__ == '__main__':
requests_session = requests.Session()
time_now = datetime.datetime.now()
pre_date = (time_now+datetime.timedelta(days=7)).strftime("%Y%m%d")
session_id = login('xxxx','xxxxxx')
if get_doctor_info(session_id,pre_date):
regno = get_time(session_id)[0]
timespan = get_time(session_id)[1]
set_doctor_number(session_id,pre_date,regno,timespan)
else:
send_message_wchat("浙一预约挂号结果","获取列表失败,可能原因:医生不在预约列表中或者医生门诊不在上午")

通过计划任务定时执行

然后写个计划任务每个月的第一个周三去执行脚本

0 15 1-7 * * if [ `date '+%w'` = "3" ]; then /usr/bin/python3 /opt/hospital/zheyi.py;fi

执行结果

执行脚本后结果

命令行式输出化验单到 markdown 文件中

另外我觉得查询化验报告的功能也不好用,每次都要登录APP 然后输入姓名 医嘱号然后查询。

我希望对自己的病情做个管理,把每次的化验结果都保存起来进行分析,于是就实现个输入医嘱号 自动输出 markdown 格式的文档里面包含一张表格,如图所示:

代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
import requests
import json



requests_session = requests.Session()

def login(username,password):

url = "https://zyyy.zwjk.com/api/exec.htm"
data = {"api_Channel":"1",
"client_version":"3.6.6",
"app_id":"zyyy_android",
"app_key":"xxx",
"user_type":"0",
"client_mobile":"863008041030718",
"api_name":"api.user.user.login.info",
"params":{"phone":username, # 账号
"psw":password}, # 密码
}
headers = {
'Content-Type': "application/x-www-form-urlencoded",
'User-Agent': "health",
'Host': "zyyy.zwjk.com",
'Connection': "Keep-Alive",
'Accept': "application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5",
'cache-control': "no-cache",
}

response = requests_session.post( url, data={"requestData":json.dumps(data)}, headers=headers)

if response.status_code != 200:
return False
resp_json = response.json()
session_id = resp_json['return_params']['user_model']['session_id']
return session_id


def get_huayan_save(session_id,username, barcode):

url = "https://zyyy.zwjk.com/api/exec.htm"
payload = {"api_Channel": "1",
"client_version": "3.6.6",
"app_id": "zyyy_android",
"app_key": "xxx",
"user_type": "0",
"client_mobile": "863008041030718",
"api_name": "api.assay.report.socket",
"params": {"name": username,
"barcode": barcode},
"session_id": session_id
}

headers = {
'Content-Type': "application/x-www-form-urlencoded",
'User-Agent': "health",
'Host': "zyyy.zwjk.com",
'Connection': "Keep-Alive",
'Accept': "application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5",
'cache-control': "no-cache",
}

response = requests_session.post(url, data={"requestData": json.dumps(payload)}, headers=headers)

if response.status_code != 200:
return False
resp_json = response.json()
if resp_json['return_params']['ret_code'] == -1:
return resp_json['return_params']['ret_info']
file_name = resp_json['return_params']['assayreport']['test_name']
username = resp_json['return_params']['assayreport']['name']
sample_type = resp_json['return_params']['assayreport']['sample_type']
report_barcode = resp_json['return_params']['assayreport']['report_barcode']
send_time = resp_json['return_params']['assayreport']['send_time']
send_name = resp_json['return_params']['assayreport']['send_name']
assayreportdetail = resp_json['return_params']['assayreportdetail']
entry_time = resp_json['return_params']['assayreport']['entry_time']
entry_name = resp_json['return_params']['assayreport']['entry_name']
audit_name = resp_json['return_params']['assayreport']['audit_name']


with open(username+file_name+"+"+report_barcode+".md","at") as f:
f.write("|项目||||"+"\n")
f.write("|---|---|---|---|"+"\n")
f.write("|化验项目|"+sample_type+"|"+file_name+"||"+"\n")
f.write("|接收时间|"+send_time+"|||"+"\n")
f.write("|报告时间|"+entry_time+"|||"+"\n")
f.write("|送检医生|"+send_name+"|||"+"\n")
f.write("|报告医生|"+entry_name+"|||"+"\n")
f.write("|审计医生|"+audit_name+"|||"+"\n")
f.write("|医嘱号|"+report_barcode+"|||"+"\n")
f.write("\n")
f.write("|项目|单位|结果|参考范围|"+"\n")
f.write("|---|---|---|---|"+"\n")
for i in assayreportdetail:
item_name_info = i['item_name']
try:
result_unit_info = i['result_unit']
result_data_info = i['result_data']
ref_range_low_info = i['ref_range_low']
except KeyError:
pass
if result_unit_info:
f.write("|"+item_name_info+"|"+str(result_unit_info)+"|"+result_data_info+"|"+ref_range_low_info+"|"+"\n")
else:
f.write("|"+item_name_info+"|"+"|"+result_data_info+"|"+ref_range_low_info+"|"+"\n")

if __name__ == '__main__':

session_id = login('xxxx','xxx')
report_barcode = input("请输入医嘱号:")
print(get_huayan_save(session_id,"阿文",report_barcode))

后面我可以把这些数据都导入Excel 之类的表格里面进行统计分析每次的指标变化。

忠告

好好的身体经不起体检,尤其是年纪越来越大,希望新的一年里,能够早日康复,也希望所有人都能够健康。生病了不要想着他自己会好,即使是自限制性病,比如感冒,也需要做好防护措施,避免加重病情。

得了这个病让我改掉了很多坏习惯,比如熬夜,喝饮料(现在都每天8杯白开水),吃辣的东西,烧烤、饮酒、高盐油腻食品等等全戒了。命比这些重要。

定期体检

为了自己也为了家人,一定要定期体检,一些常规性体检很便宜的,比如我这个病做个尿常规看下有没有隐血有没有尿蛋白就可以大概判断是泌尿系统的疾病。几十块钱,医保都可以直接报销的,花不了几个钱。