Spaces:
Sleeping
Sleeping
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""" | |
<style> | |
.stApp {{ | |
background: url(data:image/png;base64,{encoded}); | |
background-size: cover; | |
}} | |
</style> | |
""", | |
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('沒有符合條件的資料。') | |