import streamlit as st import requests from bs4 import BeautifulSoup import pandas as pd import plotly.express as px import base64 import folium from streamlit_folium import st_folium from geopy.geocoders import Nominatim # Function to set background image def set_background(png_file): with open(png_file, "rb") as f: data = f.read() encoded = base64.b64encode(data).decode() st.markdown( f""" """, unsafe_allow_html=True ) # Set the background image set_background('CAT.png') # Title of the app st.title("寵物醫院評分查詢") # User input for minimum rating min_rating = st.slider("請輸入想查詢的最低評分:", 1.0, 5.0, 3.5) # List of URLs to scrape urls = [ "https://www.tw-animal.com/pet/171211/c000196.html", "https://www.tw-animal.com/pet/171211/c000186.html", "https://www.tw-animal.com/pet/171211/c000186.html", "https://www.tw-animal.com/pet/171211/c000081.html", "https://www.tw-animal.com/pet/171211/c001166.html", "https://www.tw-animal.com/pet/171211/c000773.html", "https://www.tw-animal.com/pet/171211/c001038.html", "https://www.tw-animal.com/pet/171211/c000741.html", "https://www.tw-animal.com/pet/171211/c001451.html", "https://www.tw-animal.com/pet/171211/c000102.html", "https://www.tw-animal.com/pet/171211/c000757.html", "https://www.tw-animal.com/pet/171211/c000703.html", "https://www.tw-animal.com/pet/171211/c000481.html", "https://www.tw-animal.com/pet/171211/c000971.html", "https://www.tw-animal.com/pet/171211/c000187.html", "https://www.tw-animal.com/pet/171211/c001357.html", "https://www.tw-animal.com/pet/171211/c001065.html", "https://www.tw-animal.com/pet/171211/c000165.html", "https://www.tw-animal.com/pet/171211/c001138.html", "https://www.tw-animal.com/pet/171211/c000484.html", "https://www.tw-animal.com/pet/171211/c001089.html", "https://www.tw-animal.com/pet/171211/c001252.html" ] # Create an empty list to store the extracted data data_list = [] # Initialize the geolocator geolocator = Nominatim(user_agent="geoapiExercises") # Scrape data when the button is pressed if st.button('開始爬取資料'): st.write("正在爬取資料,請稍候...") # Loop through each URL and extract the data for url in urls: response = requests.get(url) soup = BeautifulSoup(response.content, 'html.parser') # Extract data title = soup.find('h1', class_='t-intro__title').get_text(strip=True) phone = soup.find('a', class_='t-font-large').get_text(strip=True) address = soup.find('a', class_='t-font-medium').get_text(strip=True) rating = float(soup.find('span', class_='t-intro__recommand').get_text(strip=True)) # Append the data to the list if rating meets the threshold if rating >= min_rating: try: # Geocode the address to get the latitude and longitude location = geolocator.geocode(address) if location: data_list.append({ "標題": title, "手機": phone, "地址": address, "評分": rating, "經度": location.longitude, "緯度": location.latitude }) except Exception as e: st.warning(f"無法獲取經緯度:{e}") # If data was scraped successfully if data_list: df1 = pd.DataFrame(data_list) # Extract the region from the address (assuming region is part of the address) df1['區域'] = df1['地址'].apply(lambda x: x.split()[0]) # Group by region and merge hospitals in the same region grouped_df = df1.groupby('區域').agg({ '標題': lambda x: ' | '.join(x), '手機': lambda x: ' | '.join(x), '地址': lambda x: ' | '.join(x), '評分': 'mean' # Aggregation for average rating }).reset_index() # Display the dataframe st.dataframe(df1) # Display Plotly bar chart bar_fig = px.bar(grouped_df, x='區域', y='評分', title="各區域寵物醫院統計", labels={'評分':'平均評分', '區域':'區域'}) st.plotly_chart(bar_fig) # Display Plotly pie chart pie_fig = px.pie(grouped_df, names='區域', values='評分', title="各區域寵物醫院比例") st.plotly_chart(pie_fig) # Display the map if st.button('顯示地圖'): # Create a folium map centered around the average location map_center = [df1['緯度'].mean(), df1['經度'].mean()] pet_map = folium.Map(location=map_center, zoom_start=12) # Add markers for each hospital for index, row in df1.iterrows(): folium.Marker( location=[row['緯度'], row['經度']], popup=f"{row['標題']} (評分: {row['評分']})", tooltip=row['標題'] ).add_to(pet_map) # Render the map using streamlit_folium st_folium(pet_map, width=700, height=500) # Sending notification to LINE if st.button('發送前五筆資料到Line'): msg = df1[:5].to_string(index=False) token = "DzMHaXosskpjtGuIjuB7NIcQ5TIoptLz7l7VYzV3Wp4" # Replace with your LINE Notify token # Send message to LINE def send_line_notify(token, msg): headers = { "Authorization": "Bearer " + token, "Content-Type": "application/x-www-form-urlencoded" } params = {"message": msg} r = requests.post("https://notify-api.line.me/api/notify", headers=headers, params=params) send_line_notify(token, msg) st.success('資料已成功發送到 Line!') else: st.warning('沒有符合條件的資料。')