Rooobert commited on
Commit
15b2650
·
verified ·
1 Parent(s): f315d51

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +134 -0
app.py ADDED
@@ -0,0 +1,134 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import requests
3
+ import json
4
+ import pandas as pd
5
+ import time
6
+ import matplotlib.pyplot as plt
7
+ import seaborn as sns
8
+ from datetime import datetime
9
+
10
+ # Set page config
11
+ st.set_page_config(
12
+ page_title="PChome 商品分析器",
13
+ page_icon="📊",
14
+ layout="wide"
15
+ )
16
+
17
+ # Title and description
18
+ st.title("PChome 商品分析器")
19
+ st.markdown("這個應用程式可以爬取並分析 PChome 上的商品資訊")
20
+
21
+ # Input section
22
+ with st.sidebar:
23
+ st.header("搜尋設定")
24
+ keyword = st.text_input("請輸入搜尋關鍵字", "行李箱")
25
+ page_num = st.number_input("要爬取的頁數", min_value=1, max_value=10, value=1)
26
+
27
+ # Function to scrape PChome data
28
+ def scrape_pchome(keyword, page_num):
29
+ alldata = pd.DataFrame()
30
+
31
+ with st.spinner(f'正在爬取 {page_num} 頁的資料...'):
32
+ for i in range(1, page_num + 1):
33
+ # Progress bar
34
+ progress = st.progress((i - 1) / page_num)
35
+
36
+ url = f'https://ecshweb.pchome.com.tw/search/v3.3/all/results?q={keyword}&page={i}&sort=sale/dc'
37
+
38
+ try:
39
+ list_req = requests.get(url)
40
+ getdata = json.loads(list_req.content)
41
+
42
+ if 'prods' in getdata and getdata['prods']:
43
+ todataFrame = pd.DataFrame(getdata['prods'])
44
+ alldata = pd.concat([alldata, todataFrame])
45
+
46
+ time.sleep(2) # Reduced sleep time for better user experience
47
+
48
+ except Exception as e:
49
+ st.error(f"爬取第 {i} 頁時發生錯誤: {str(e)}")
50
+ break
51
+
52
+ progress.progress((i) / page_num)
53
+
54
+ return alldata
55
+
56
+ # Function to create analysis plots
57
+ def create_analysis_plots(df):
58
+ # Basic statistics
59
+ st.subheader("基本統計資訊")
60
+ col1, col2, col3 = st.columns(3)
61
+ with col1:
62
+ st.metric("平均價格", f"NT$ {df['price'].mean():,.0f}")
63
+ with col2:
64
+ st.metric("最高價格", f"NT$ {df['price'].max():,.0f}")
65
+ with col3:
66
+ st.metric("最低價格", f"NT$ {df['price'].min():,.0f}")
67
+
68
+ # Price trend plot
69
+ st.subheader("價格趨勢圖")
70
+ fig, ax = plt.subplots(figsize=(15, 8))
71
+ df['price'][:70].plot(
72
+ color='skyblue',
73
+ linewidth=2,
74
+ marker='o',
75
+ markersize=8,
76
+ ax=ax
77
+ )
78
+
79
+ mean_price = df['price'].mean()
80
+ ax.axhline(y=mean_price, color='red', linestyle='--', linewidth=2,
81
+ label=f'平均價格: NT$ {mean_price:,.0f}')
82
+
83
+ plt.title(f'{datetime.now().strftime("%Y%m%d")} PChome {keyword} 售價分析',
84
+ fontsize=20, fontweight='bold')
85
+ plt.xlabel('商品編號', fontsize=14)
86
+ plt.ylabel('價格 (NT$)', fontsize=14)
87
+ plt.xticks(rotation=45)
88
+ plt.grid(True, alpha=0.3)
89
+ plt.legend()
90
+ st.pyplot(fig)
91
+
92
+ # Price distribution plot
93
+ st.subheader("價格分布圖")
94
+ fig2, ax2 = plt.subplots(figsize=(12, 6))
95
+ sns.histplot(data=df['price'], bins=30, kde=True, ax=ax2)
96
+ plt.title('商品價格分布', fontsize=16)
97
+ plt.xlabel('價格 (NT$)', fontsize=12)
98
+ plt.ylabel('數量', fontsize=12)
99
+ st.pyplot(fig2)
100
+
101
+ # Main app logic
102
+ if st.sidebar.button('開始分析'):
103
+ # Record start time
104
+ start_time = time.time()
105
+
106
+ # Scrape data
107
+ data = scrape_pchome(keyword, page_num)
108
+
109
+ if not data.empty:
110
+ # Display raw data
111
+ st.subheader("原始資料")
112
+ st.dataframe(data[['name', 'price']])
113
+
114
+ # Create analysis plots
115
+ create_analysis_plots(data)
116
+
117
+ # Download button for CSV
118
+ csv = data.to_csv(index=False).encode('utf-8-sig')
119
+ st.download_button(
120
+ label="下載完整資料 (CSV)",
121
+ data=csv,
122
+ file_name=f'pchome_{keyword}_{datetime.now().strftime("%Y%m%d")}.csv',
123
+ mime='text/csv'
124
+ )
125
+
126
+ # Display execution time
127
+ end_time = time.time()
128
+ st.info(f'分析完成!執行時間:{end_time - start_time:.2f} 秒')
129
+ else:
130
+ st.error("沒有找到相關商品資料")
131
+
132
+ # Footer
133
+ st.markdown("---")
134
+ st.markdown("Made with ❤️ by Your Name")