Spaces:
Sleeping
Sleeping
import os | |
import requests | |
import pandas as pd | |
import json | |
import time | |
import matplotlib as mpl | |
import matplotlib.font_manager as fm | |
import matplotlib.pyplot as plt | |
import streamlit as st | |
# Streamlit 應用程式標題 | |
st.title('電商商品價格分析 - MOMO & PChome') | |
# 從使用者獲取搜索關鍵字和頁數 | |
search_keyword = st.text_input("請輸入要搜索的關鍵字:", "手機") | |
page_number = st.number_input("請輸入要搜索的頁數:", min_value=1, value=1) | |
if st.button('搜索'): | |
momo_data = pd.DataFrame() | |
pchome_data = pd.DataFrame() | |
# MOMO 平台搜索邏輯 | |
momo_url = "https://apisearch.momoshop.com.tw/momoSearchCloud/moec/textSearch" | |
momo_headers = { | |
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36" | |
} | |
momo_payload = { | |
"host": "momoshop", | |
"flag": "searchEngine", | |
"data": { | |
"searchValue": search_keyword, | |
"curPage": str(page_number), | |
"priceS": "0", | |
"priceE": "9999999", | |
"searchType": "1" | |
} | |
} | |
momo_response = requests.post(momo_url, headers=momo_headers, json=momo_payload) | |
if momo_response.status_code == 200: | |
momo_data_from_api = momo_response.json() | |
momo_products = momo_data_from_api.get('rtnSearchData', {}).get('goodsInfoList', []) | |
momo_product_list = [] | |
for product in momo_products: | |
name = product.get('goodsName', '') | |
price = product.get('goodsPrice', '') | |
price_str = str(price) | |
if '(' in price_str: | |
price_str = price_str.split('(')[0] | |
price_str = price_str.replace(',', '').replace('$', '') | |
try: | |
product_price = float(price_str) | |
except ValueError: | |
product_price = 0 | |
momo_product_list.append({'title': name, 'price': product_price}) | |
momo_data = pd.DataFrame(momo_product_list) | |
else: | |
st.error(f"MOMO 請求失敗,狀態碼: {momo_response.status_code}") | |
# PChome 平台搜索邏輯 | |
for i in range(1, page_number + 1): | |
pchome_url = f'https://ecshweb.pchome.com.tw/search/v3.3/all/results?q={search_keyword}&page={i}&sort=sale/dc' | |
pchome_list_req = requests.get(pchome_url) | |
if pchome_list_req.status_code == 200: | |
pchome_getdata = json.loads(pchome_list_req.content) | |
pchome_todataFrame = pd.DataFrame(pchome_getdata['prods']) | |
pchome_todataFrame.rename(columns={'name': 'title'}, inplace=True) | |
pchome_data = pd.concat([pchome_data, pchome_todataFrame]) | |
time.sleep(1) # Respectful delay | |
else: | |
st.error(f"PChome 請求失敗,狀態碼: {pchome_list_req.status_code}") | |
# 計算 MOMO 的統計數據 | |
if not momo_data.empty: | |
momo_max_price = momo_data['price'].max() | |
momo_min_price = momo_data['price'].min() | |
momo_max_product = momo_data[momo_data['price'] == momo_max_price]['title'].values[0] | |
momo_min_product = momo_data[momo_data['price'] == momo_min_price]['title'].values[0] | |
momo_mean_price = momo_data['price'].mean() | |
st.subheader("MOMO 統計數據") | |
st.write(f"最高價格商品: {momo_max_product}") | |
st.write(f"價格: {momo_max_price}") | |
st.write(f"最低價格商品: {momo_min_product}") | |
st.write(f"價格: {momo_min_price}") | |
st.write(f"平均價格: {momo_mean_price:.2f}") | |
# 顯示 MOMO 的 DataFrame | |
st.write(momo_data[['title', 'price']]) | |
# 計算 PChome 的統計數據 | |
if not pchome_data.empty: | |
pchome_max_price = pchome_data['price'].max() | |
pchome_min_price = pchome_data['price'].min() | |
pchome_max_product = pchome_data[pchome_data['price'] == pchome_max_price]['title'].values[0] | |
pchome_min_product = pchome_data[pchome_data['price'] == pchome_min_price]['title'].values[0] | |
pchome_mean_price = pchome_data['price'].mean() | |
st.subheader("PChome 統計數據") | |
st.write(f"最高價格商品: {pchome_max_product}") | |
st.write(f"價格: {pchome_max_price}") | |
st.write(f"最低價格商品: {pchome_min_product}") | |
st.write(f"價格: {pchome_min_price}") | |
st.write(f"平均價格: {pchome_mean_price:.2f}") | |
# 顯示 PChome 的 DataFrame | |
st.write(pchome_data[['title', 'price']]) | |
# 繪製合併的價格點狀圖 | |
if not momo_data.empty or not pchome_data.empty: | |
# 字型設定 | |
font_url = 'https://github.com/googlefonts/noto-cjk/raw/main/Sans/OTF/TraditionalChinese/NotoSansCJKtc-Regular.otf' | |
font_response = requests.get(font_url) | |
font_path = 'NotoSansCJKtc-Regular.otf' | |
with open(font_path, "wb") as font_file: | |
font_file.write(font_response.content) | |
fm.fontManager.addfont(font_path) | |
mpl.rc('font', family='Noto Sans CJK TC') | |
# 合併兩個 DataFrame | |
momo_data['platform'] = 'MOMO' | |
pchome_data['platform'] = 'PChome' | |
all_data = pd.concat([momo_data, pchome_data]) | |
# 繪製價格點狀圖 | |
fig, ax = plt.subplots(figsize=(10, 6)) | |
for platform in all_data['platform'].unique(): | |
platform_data = all_data[all_data['platform'] == platform] | |
ax.scatter(platform_data.index, platform_data['price'], label=platform, s=100, alpha=0.7) | |
ax.set_title(f'電商平台 "{search_keyword}" 價格比較 - MOMO & PChome', fontsize=20, fontweight='bold') | |
ax.set_xlabel('商品 ID', fontsize=14) | |
ax.set_ylabel('價格', fontsize=14) | |
ax.axhline(y=all_data['price'].mean(), color='red', linestyle='--', linewidth=2, label=f'總平均價格: {all_data["price"].mean():.2f}') | |
ax.legend(fontsize=10, loc='upper left') | |
ax.grid(axis='y', linestyle='--', alpha=0.5) | |
ax.set_facecolor('#f8f8f8') | |
plt.tight_layout() | |
st.pyplot(fig) | |
os.remove(font_path) | |
else: | |
st.warning("未能從 MOMO 或 PChome 獲取到數據") | |