Pikachu0309/20250412_law
0
1import streamlit as st2 3# ✅ st.set_page_config 必須是第一個 Streamlit 命令4st.set_page_config(5 page_title="最新法規爬蟲工具",6 page_icon="⚖️",7 layout="wide"8)9 10import requests11from bs4 import BeautifulSoup12import pandas as pd13import re14import base6415from io import BytesIO16import plotly.graph_objects as go17from plotly.subplots import make_subplots18import plotly.express as px19 20# 設定背景圖片21def set_background(png_file):22 with open(png_file, "rb") as f:23 data = f.read()24 encoded_data = base64.b64encode(data).decode()25 st.markdown(26 f"""27 <style>28 .stApp {{29 background-image: url(data:image/png;base64,{encoded_data});30 background-size: cover;31 }}32 </style>33 """,34 unsafe_allow_html=True35 )36 37# 設定背景圖為law.png38set_background('law.png')39 40# 網頁標題和介紹41st.title("⚖️ 最新法規爬蟲工具 ⚖️")42st.markdown("這個應用程式可以從台灣法務部網站抓取法規資訊。您可以指定抓取的資料筆數和目標網址。")43 44# 側邊欄設置45with st.sidebar:46 st.header("設定")47 url = st.text_input("目標網址", "https://law.moj.gov.tw/")48 max_items = st.slider("抓取筆數", 1, 30, 10)49 50 st.markdown("---")51 st.markdown("### 關於")52 st.markdown("此工具使用 Python 的 BeautifulSoup 和 requests 庫來爬取法務部網站的法規資訊。")53 st.markdown("資料僅供參考,請以法務部官方公告為準。")54 55# 定義爬蟲函數56@st.cache_data(ttl=3600)57def scrape_moj_website(url, max_items=10):58 headers = {59 'User-Agent': 'Mozilla/5.0'60 }61 try:62 with st.spinner(f"正在從 {url} 抓取資料..."):63 response = requests.get(url, headers=headers)64 response.raise_for_status()65 soup = BeautifulSoup(response.text, 'html.parser')66 results = []67 68 news_table = soup.find('table', {'class': 'table'})69 if news_table:70 rows = news_table.find_all('tr')71 for row in rows:72 cells = row.find_all('td')73 if len(cells) >= 3:74 try:75 publish_date = cells[0].text.strip()76 law_type = cells[1].text.strip()77 content_cell = cells[2].find('a')78 if content_cell:79 content = content_cell.text.strip()80 content_url = content_cell.get('href', '')81 if content_url and not content_url.startswith('http'):82 if content_url.startswith('/'):83 base_url = '/'.join(url.split('/')[:3])84 content_url = base_url + content_url85 else:86 content_url = url.rstrip('/') + '/' + content_url87 88 results.append({89 '發布時間': publish_date,90 '法條類型': law_type,91 '條文': content,92 '連結': content_url93 })94 95 if len(results) >= max_items:96 break97 except Exception as e:98 st.warning(f"處理行時出錯: {e}")99 continue100 101 if len(results) < max_items:102 st.warning(f"無法從網站找到足夠的資料,將添加示例資料至 {max_items} 筆")103 num_to_add = max_items - len(results)104 for i in range(num_to_add):105 results.append({106 '發布時間': f'114-04-{12+i}',107 '法條類型': '法規草案',108 '條文': f'示例法規 #{i+1}',109 '連結': 'https://gazette.nat.gov.tw/egFront/detail.do?metaid=156524&log=detailLog'110 })111 112 return pd.DataFrame(results)113 114 except Exception as e:115 st.error(f"抓取資料時發生錯誤: {e}")116 data = []117 for i in range(max_items):118 data.append({119 '發布時間': f'114-04-{12+i}',120 '法條類型': '法規草案',121 '條文': f'示例法規 #{i+1}',122 '連結': 'https://gazette.nat.gov.tw/egFront/detail.do?metaid=156524&log=detailLog'123 })124 return pd.DataFrame(data)125 126# 下載功能127 128def get_csv_download_link(df, filename="data.csv"):129 csv = df.to_csv(index=False, encoding='utf-8-sig')130 b64 = base64.b64encode(csv.encode('utf-8-sig')).decode()131 href = f'<a href="data:file/csv;base64,{b64}" download="{filename}">點擊下載 CSV 檔案</a>'132 return href133 134def get_excel_download_link(df, filename="data.xlsx"):135 output = BytesIO()136 writer = pd.ExcelWriter(output, engine='xlsxwriter')137 df.to_excel(writer, index=False, sheet_name='法規資料')138 writer.close()139 processed_data = output.getvalue()140 b64 = base64.b64encode(processed_data).decode()141 href = f'<a href="data:application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;base64,{b64}" download="{filename}">點擊下載 Excel 檔案</a>'142 return href143 144# 主程式區域145col1, col2 = st.columns([3, 1])146 147with col2:148 if st.button("開始抓取", type="primary", use_container_width=True):149 st.session_state.df = scrape_moj_website(url, max_items)150 st.session_state.scraped = True151 152 if st.button("清除資料", type="secondary", use_container_width=True):153 st.session_state.pop('df', None)154 st.session_state.pop('scraped', None)155 156with col1:157 if 'scraped' in st.session_state and 'df' in st.session_state:158 st.success(f"已成功抓取 {len(st.session_state.df)} 筆資料")159 st.dataframe(st.session_state.df, use_container_width=True)160 161 st.markdown("### 下載選項")162 col_a, col_b = st.columns(2)163 with col_a:164 st.markdown(get_csv_download_link(st.session_state.df, "法務部法規資料.csv"), unsafe_allow_html=True)165 with col_b:166 st.markdown(get_excel_download_link(st.session_state.df, "法務部法規資料.xlsx"), unsafe_allow_html=True)167 else:168 st.info("請點擊「開始抓取」按鈕來獲取法規資料")169 170# 資料分析171if 'scraped' in st.session_state and 'df' in st.session_state and not st.session_state.df.empty:172 with st.expander("📊 資料分析"):173 st.subheader("法條類型分布")174 type_counts = st.session_state.df['法條類型'].value_counts().reset_index()175 type_counts.columns = ['法條類型', '數量']176 st.bar_chart(type_counts.set_index('法條類型'))177 178 st.subheader("發布時間分布")179 date_counts = st.session_state.df['發布時間'].value_counts().sort_index().reset_index()180 date_counts.columns = ['發布時間', '數量']181 st.line_chart(date_counts.set_index('發布時間'))182 183 st.subheader("基本統計")184 st.write(f"- 總筆數: {len(st.session_state.df)}")185 st.write(f"- 不同法條類型數量: {st.session_state.df['法條類型'].nunique()}")186 st.write(f"- 平均條文長度: {st.session_state.df['條文'].str.len().mean():.1f} 字元")187 188# 頁腳189st.markdown("---")190st.markdown("### 使用說明")191st.markdown("""1921. 在側邊欄設定目標網址和要抓取的筆數1932. 點擊「開始抓取」按鈕進行資料抓取1943. 查看結果並下載資料1954. 使用「清除資料」按鈕清除當前結果196""")197 