Roberta2024 commited on
Commit
1d21670
·
verified ·
1 Parent(s): 26d034c

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +158 -0
app.py ADDED
@@ -0,0 +1,158 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import smtplib
2
+ from email.mime.text import MIMEText
3
+ from email.mime.multipart import MIMEMultipart
4
+ from email.mime.image import MIMEImage
5
+ import streamlit as st
6
+ import requests
7
+ from bs4 import BeautifulSoup
8
+ import pandas as pd
9
+ import plotly.express as px
10
+
11
+ # 定義爬取數據的函數
12
+ def fetch_data(hospital_url, table_id, hospital_name):
13
+ response = requests.get(hospital_url)
14
+ soup = BeautifulSoup(response.text, 'html.parser')
15
+ table = soup.find('table', {'id': table_id})
16
+ if not table:
17
+ return pd.DataFrame() # 若表格未找到,返回空的DataFrame
18
+
19
+ rows = table.find_all('tr')
20
+ data = []
21
+
22
+ if hospital_name == "成大醫院":
23
+ columns = [th.text.strip() for th in rows[0].find_all("th")]
24
+ columns = ['病床種類' if col == '病床類別' else col for col in columns]
25
+ data_rows = rows[1:]
26
+ for row in data_rows:
27
+ row_data = [td.text.strip() for td in row.find_all("td")]
28
+ if all(row_data):
29
+ data.append(row_data)
30
+ else:
31
+ columns = ['病床種類', '病床數', '住院人數', '空床數', '佔床率']
32
+ for row in rows[1:]:
33
+ cols = row.find_all('td')
34
+ if len(cols) == 5:
35
+ row_data = [col.get_text(strip=True) for col in cols]
36
+ if all(row_data):
37
+ data.append(row_data)
38
+
39
+ df = pd.DataFrame(data, columns=columns)
40
+
41
+ if '病床數' not in df.columns and '開放床數' in df.columns:
42
+ df = df.rename(columns={'開放床數': '病床數'})
43
+
44
+ return df
45
+
46
+ # Streamlit UI
47
+ st.title("醫院床位分配表爬取工具")
48
+
49
+ # 下拉式選單選擇醫院
50
+ hospital_options = {
51
+ "台南醫院": {
52
+ "url": "https://www.tmh.org.tw/tmh2016/ImpBD.aspx?Kind=2",
53
+ "table_id": "ctl00_ContentPlaceHolder1_GV_Bed"
54
+ },
55
+ "奇美醫院": {
56
+ "url": "https://www.chimei.org.tw/%E4%BD%94%E5%BA%8A%E7%8E%87%E6%9F%A5%E8%A9%A2/%E4%BD%94%E5%BA%8A%E7%8E%87%E6%9F%A5%E8%A9%A2.aspx?ihospital=10&ffloor=",
57
+ "table_id": "DG1"
58
+ },
59
+ "成大醫院": {
60
+ "url": "https://web.hosp.ncku.edu.tw/nckm/Bedstatus/BedStatus.aspx",
61
+ "table_id": "GV_EmgInsure"
62
+ }
63
+ }
64
+
65
+ selected_hospitals = st.multiselect("選擇醫院", list(hospital_options.keys()))
66
+
67
+ # 手動輸入收件人的電子郵件地址
68
+ to_addr_list = []
69
+ email_input = st.text_input("請輸入收件人的電子郵件地址,使用逗號分隔多個地址")
70
+
71
+ if email_input:
72
+ to_addr_list = [email.strip() for email in email_input.split(",")]
73
+
74
+ # 當用戶按下按鈕時,開始爬取數據
75
+ if st.button("爬取資料並發送郵件"):
76
+ st.write("正在爬取資料...")
77
+ all_data = pd.DataFrame()
78
+
79
+ for hospital_name in selected_hospitals:
80
+ hospital_data = hospital_options[hospital_name]
81
+ df = fetch_data(hospital_data["url"], hospital_data["table_id"], hospital_name)
82
+ if df.empty:
83
+ st.warning(f"{hospital_name} 的數據爬取結果為空,請檢查是否存在問題。")
84
+ else:
85
+ df['醫院'] = hospital_name
86
+ all_data = pd.concat([all_data, df], ignore_index=True)
87
+
88
+ if not all_data.empty:
89
+ st.write("爬取完成,合併的數據如下:")
90
+ st.dataframe(all_data)
91
+
92
+ # 繪製圖表
93
+ st.write("正在繪製圖表...")
94
+ bed_column = '病床數'
95
+ all_data[bed_column] = pd.to_numeric(all_data[bed_column], errors='coerce')
96
+ bed_counts = all_data.groupby(['醫院', '病床種類'])[bed_column].sum().reset_index()
97
+
98
+ # 圓餅圖
99
+ fig_pie = px.pie(bed_counts, values=bed_column, names='病床種類', title='各類型病床分佈',
100
+ hover_data=['醫院'], labels={bed_column: '病床數'})
101
+ st.plotly_chart(fig_pie)
102
+
103
+ # 保存圓餅圖為文件
104
+ fig_pie.write_image("pie_chart.png")
105
+
106
+ # 柱狀圖
107
+ fig_bar = px.bar(bed_counts, x='醫院', y=bed_column, color='病床種類', title='醫院病床分佈',
108
+ labels={bed_column: '病床數'}, barmode='group')
109
+ st.plotly_chart(fig_bar)
110
+
111
+ # 保存柱狀圖為文件
112
+ fig_bar.write_image("bar_chart.png")
113
+
114
+ # 格式化數據為電子郵件內容
115
+ email_body = "以下為最新醫院床位分配數據:\n\n"
116
+ email_body += all_data.to_string(index=False)
117
+
118
+ # 構建郵件
119
+ msg = MIMEMultipart()
120
+ msg['Subject'] = '會員通知'
121
+ msg['From'] = '[email protected]'
122
+ msg['To'] = ', '.join(to_addr_list)
123
+
124
+ # 添加文本內容
125
+ msg.attach(MIMEText(email_body, 'plain', 'utf-8'))
126
+
127
+ # 添加圖表圖片
128
+ for image_path in ['pie_chart.png', 'bar_chart.png']:
129
+ with open(image_path, 'rb') as img_file:
130
+ img = MIMEImage(img_file.read())
131
+ img.add_header('Content-Disposition', f'attachment; filename="{image_path}"')
132
+ msg.attach(img)
133
+
134
+ # 發送郵件給所有輸入的收件人
135
+ if to_addr_list:
136
+ st.write("正在發送郵件...")
137
+ smtp_server = 'smtp.gmail.com'
138
+ smtp_port = 587
139
+ from_addr = '[email protected]'
140
+ pwd = 'hedm elps tksg'
141
+
142
+ mySMTP = smtplib.SMTP(smtp_server, smtp_port)
143
+ mySMTP.ehlo()
144
+ mySMTP.starttls()
145
+ mySMTP.login(from_addr, pwd)
146
+
147
+ try:
148
+ mySMTP.sendmail(from_addr, to_addr_list, msg.as_string())
149
+ st.success("成功發送郵件")
150
+ except Exception as e:
151
+ st.error(f"發送郵件失敗: {e}")
152
+
153
+ mySMTP.quit()
154
+ else:
155
+ st.warning("請輸入至少一個有效的電子郵件地址。")
156
+
157
+ else:
158
+ st.error("沒有成功爬取任何數據。")