import pandas as pd from bs4 import BeautifulSoup import requests import streamlit as st import plotly.express as px import io import tempfile # Function to send messages and images via LINE def send_line_message(channel_access_token, user_id, df, img_paths): line_bot_api = LineBotApi(channel_access_token) # Send DataFrame as a text message text_message = TextSendMessage(text=df.to_string()) line_bot_api.push_message(user_id, text_message) # Send images for img_path in img_paths: image_message = ImageSendMessage(original_content_url=img_path, preview_image_url=img_path) line_bot_api.push_message(user_id, image_message) def fetch_table_data(url, table_id, has_header=True, rename_columns=None, drop_columns=None, custom_columns=None): response = requests.get(url) soup = BeautifulSoup(response.text, "html.parser") table = soup.find("table", {"id": table_id}) if not table: st.warning(f"在 {url} 中找不到 ID 為 {table_id} 的表格") return pd.DataFrame() rows = table.find_all("tr") if not rows: st.warning(f"在 {url} 中,ID 為 {table_id} 的表格中找不到任何行") return pd.DataFrame() if has_header: columns = [th.text.strip() for th in rows[0].find_all("th")] data = [] for row in rows[1:]: row_data = [td.text.strip() for td in row.find_all("td")] if row_data: data.append(row_data) else: columns = custom_columns data = [] for row in rows: row_data = [td.text.strip() for td in row.find_all("td")] if row_data: data.append(row_data) if not data: st.warning(f"在 {url} 中,ID 為 {table_id} 的表格中找不到任何資料行") return pd.DataFrame() if len(columns) > 0: for i, row in enumerate(data): if len(row) != len(columns): st.warning(f"資料行 {i+1} 的列數與標題列數不一致:{len(row)} vs {len(columns)}") return pd.DataFrame() df = pd.DataFrame(data, columns=columns) if rename_columns: df = df.rename(columns=rename_columns) if drop_columns: df = df.drop(columns=drop_columns) return df def calculate_stats(df): df["病床數"] = pd.to_numeric(df["病床數"], errors='coerce') df["佔床數"] = pd.to_numeric(df["佔床數"], errors='coerce') df["空床數"] = df["病床數"] - df["佔床數"] total_beds = df["病床數"].sum() occupied_beds = df["佔床數"].sum() occupancy_rate = (occupied_beds / total_beds) * 100 if total_beds > 0 else 0 return total_beds, occupied_beds, occupancy_rate def main(): st.title("👩‍🍼🚑台南醫院病床狀態查詢🐇") url1 = "https://www.tmh.org.tw/tmh2016/ImpBD.aspx?Kind=2" url2 = "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=" url3 = "https://web.hosp.ncku.edu.tw/nckm/Bedstatus/BedStatus.aspx" table_id1 = "ctl00_ContentPlaceHolder1_GV_Bed" table_id2 = "DG1" table_id3 = "GV_EmgInsure" df1 = fetch_table_data(url1, table_id1, rename_columns={'床位別數':'病床數', '住院人數':'佔床數'}, drop_columns=['佔床率']) df2 = fetch_table_data(url2, table_id2, has_header=False, custom_columns=["病床類別", "病床數", "佔床數", "空床數", "佔床率"], drop_columns=['佔床率']) df3 = fetch_table_data(url3, table_id3) if not df1.empty: df1 = df1.rename(columns={'病床種類':'病床類別'}) df1['醫院'] = '台南市立醫院' if not df2.empty: df2 = df2.drop(index=0) df2['醫院'] = '奇美醫院' if not df3.empty: df3['醫院'] = '成大醫院' combined_df = pd.concat([df for df in [df1, df2, df3] if not df.empty], ignore_index=True) hospital_choice = st.selectbox( "選擇醫院或顯示合併數據", ("台南市立醫院", "奇美醫院", "成大醫院", "三間醫院合併顯示") ) def plot_hospital_data(df, hospital_name): total_beds, occupied_beds, occupancy_rate = calculate_stats(df) st.subheader(hospital_name) st.write(f"總病床數: {total_beds}") st.write(f"佔床數: {occupied_beds}") st.write(f"佔床率: {occupancy_rate:.2f}%") df_long = df.melt(id_vars=["病床類別"], value_vars=["病床數", "佔床數", "空床數"], var_name="類型", value_name="數量") fig = px.bar(df_long, x="病床類別", y="數量", color="類型", barmode="group", title=f"{hospital_name}病床狀況") st.write(df) st.plotly_chart(fig) if hospital_choice == "台南市立醫院" and not df1.empty: plot_hospital_data(df1, "台南市立醫院") elif hospital_choice == "奇美醫院" and not df2.empty: plot_hospital_data(df2, "奇美醫院") elif hospital_choice == "成大醫院" and not df3.empty: plot_hospital_data(df3, "成大醫院") elif hospital_choice == "三間醫院合併顯示" and not combined_df.empty: total_beds, occupied_beds, occupancy_rate = calculate_stats(combined_df) st.subheader("合併後的數據") st.write(f"總病床數: {total_beds}") st.write(f"佔床數: {occupied_beds}") st.write(f"佔床率: {occupancy_rate:.2f}%") combined_df_long = combined_df.melt(id_vars=["醫院", "病床類別"], value_vars=["病床數", "佔床數", "空床數"], var_name="類型", value_name="數量") fig = px.bar(combined_df_long, x="醫院", y="數量", color="類型", barmode="group", title="合併後的病床狀況") st.write(combined_df) st.plotly_chart(fig) # 新增三個按鈕並排放置,並放大圓餅圖尺寸 col1, col2, col3 = st.columns(3) with col1: if st.button("顯示圓餅圖:病床數"): fig_pie = px.pie(combined_df, names="醫院", values="病床數", title="合併後各醫院病床總數分布") fig_pie.update_layout(width=600, height=600) # 調整圓餅圖的尺寸 st.plotly_chart(fig_pie) with col2: if st.button("顯示圓餅圖:佔床數"): fig_pie2 = px.pie(combined_df, names="醫院", values="佔床數", title="合併後各醫院佔床總數分布") fig_pie2.update_layout(width=600, height=600) # 調整圓餅圖的尺寸 st.plotly_chart(fig_pie2) with col3: if st.button("顯示圓餅圖:空床數"): fig_pie3 = px.pie(combined_df, names="醫院", values="空床數", title="合併後各醫院空床總數分布") fig_pie3.update_layout(width=600, height=600) # 調整圓餅圖的尺寸 st.plotly_chart(fig_pie3) if __name__ == "__main__": main()