告別排隊!用Python定時自動掛號和快捷查詢化驗報告

AI科技大本營發表於2019-02-07

640?wx_fmt=jpeg


作者 | 阿文

來源 | 程式人生(ID: coder_life)


我什麼要做這個事情


去年單位體檢查出問題來,經過穿刺手術確診是個慢性腎臟病2期, IGA 腎病三期,可能大家對於這個病並不是很瞭解,但是另外一個詞可能大家都聽過,叫"尿毒症"。


慢性腎臟病分五期,終末期就是尿毒症。慢性腎臟病非常隱祕,並且病情進展緩慢,一般到尿毒症需要0-20年時間,如果不是體檢化驗尿液看裡面的隱血和尿蛋白指標,根本沒任何感覺。


三甲醫院人滿為患,掛號跟春運買火車票一樣的,很麻煩。所以我打算用程式設計師的方式來解決掛號這件事。


實現自動掛號程式碼


於是就自己通過 Charles 抓包分析了醫院的 App 的請求,這裡是分析浙江大學第一附屬醫院的 App,然後用 Python 寫了個指令碼去模擬登入醫院的 App 然後去掛號,具體程式碼如下:


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

執行指令碼後結果:

640?wx_fmt=png


命令列式輸出化驗單到 markdown 檔案中


我覺得查詢化驗報告的功能不好用,每次都要登入App 然後輸入姓名和醫囑號才能查詢。


我希望對自己的病情做個管理,把每次的化驗結果都儲存起來進行分析,於是就實現只要輸入醫囑號,就自動輸出 markdown 格式的文件裡面包含一張表格,如圖所示:


640?wx_fmt=png

程式碼如下:

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":"ZW5sNWVWOWhibVJ5YjJsaw==",
            "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""ZW5sNWVWOWhibVJ5YjJsaw==",
                    "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 之類的表格裡面進行統計分析每次的指標變化。


最後


年紀越大身體經不起體檢,希望新的一年裡,能夠早日康復,也希望所有人都能夠健康。


現在我改掉了很多壞習慣,比如熬夜、喝飲料,不吃辣、不燒烤、不飲酒、不吃高鹽油膩食品等,命比這些重要。最後提醒大家,為了自己也為了家人,一定要定期體檢。

(本文為 AI科技大本營轉載文章,轉載請聯絡原作者


徵稿

640?wx_fmt=png


推薦閱讀:

點選“閱讀原文”,開啟CSDN APP 閱讀更貼心!

相關文章