爬蟲實作-TWSE公開資料觀測站

來源網站
公開資訊觀測站 - 臺灣證券交易所
-
爬取資源 :採用IFRSs後每月營業收入彙總表

-
完整程式碼我有放在
github上
前言
當你手上持有一支股票的時候,應該除了會時常看盤關注股價漲跌,也會想關注這家公司最近是否有在賺錢,最直接就是看公司的月營收,在公開資訊觀測站 - 臺灣證券交易所裡面可以查到上市上櫃歷年來目前為止的每個月營收,但當你手上有十支股票時,你必須在一張表格找十次,且每個月都要做一次,是否有點麻煩? 身為懶人的我決定透過程式來讓我一鍵產生我想要報表
事先準備
在這邊我用到就是PYTHON的爬蟲,並且運用一些套件讓我可以將資訊呈現成圖表
-
requests: 用於發送HTTP請求,通常用於從網頁獲取資料。
-
bs4 (BeautifulSoup): 用於解析HTML和XML文件,提供簡單而直覺的方法來導覽和檢索網頁資料。
-
PrettyTable: 用於將資料以表格形式輸出,使輸出更加可讀。
-
matplotlib.pyplot: 用於繪製各種圖表和視覺化。
-
PySimpleGUI: 一個簡單而直覺的GUI(圖形用戶界面)框架,用於建立基本的圖形界面應用程式。
-
可以先執行以下命令確保之後運行順利
📋1.取得資料
1.解析網頁,著尋目標
可以看到我們想要爬取的表格在第三層的TABLE裡面,是屬於巢狀表格的結構
- (當然也可以匯出成CSV,透過網址自動匯出CSV,之後的工作就會是針對工作表去做解析,比較不需要解決網頁結構HTML問題)
2.爬取目標資訊
- 一般爬蟲的做法都是藉由標籤 (Tag) 來定位,透過搭配指定屬性(ID、CLASS)可以確保找到指定段落, 但是巢狀結構,不建議使用標籤屬性定位來爬取,因為有可能可以第一個表格,但第二個就抓不到
- 關於如何爬我會先這樣寫 ,去測試是否抓到某公司的單筆數據
- 發送 HTTP 請求、並定義了一個函數
get_company_basic_data
,接受兩個參數(company_id 是要搜索的公司ID,url 是要爬取的網頁的URL),初始化一個空字典 data 來存放爬取到的數據。
- 使用
find('table')
找到 HTML 中的第一個"table"標籤,即目標巢狀表格,再透過使用 find_all('td')
找到每一行中的所有列,確保該行包含數據而不是空行,接者就可以對每一列的每一個單元格進行提取
- 使用
get_company_basic_data
函數爬取特定公司ID的數據,
4.可以看到順利得到結果

📋2.控制輸入及資料輸出
1. 解析網址特性,參數化
輸入格式ex : id(2330)year(111,112)month(1,3),就可以得到2330(TSMC)的111-112年1-3月的資料囉
<為了方便,自己創造的輸入code :+1: >
2.資料輸出
- 若有多筆資料從字典印出會不易閱讀,所以輸出我採用建立一個 PrettyTable 物件來以表格呈現 ,並且按公司代號排序,方便閱讀
- 只是從網站印出原始資料似乎有點無聊吧,於是我就額外產生每年度的營收平均值透過我們產生的資料
記得要放在for company_id, group in groupby(sorted_data, key=lambda x: x['公司代號']):
迴圈裡面
input : id(2330)year(111,112)month(1,3)

📋3. 包裝成GUI
- 因為若要時常使用,終端機的介面還是不太適合,所以我採用PySimpleGUI 布局,並將輸入分為三個輸入框:公司代號、年份範圍、月份範圍,同時會有input_log的設定這樣下次進來就會記得上次輸入的組合
1.介面基礎設計
因為介面都是顯示在PySimpleGUI,所以上面提到 print_results的部分就可以刪除
- 保存輸入進log以及PySimpleGUI layout
def parse_range(input_range):
result = []
for part in input_range:
if '-' in part:
start, end = map(int, part.split('-'))
result.extend(range(start, end + 1))
else:
result.append(int(part))
return result
def read_input_log(file_path):
input_log = []
try:
with open(file_path, 'r') as file:
lines = file.readlines()
for line in lines[-5:]:
input_log.append(line.strip())
except FileNotFoundError:
pass
return input_log
def save_input_log(file_path, input_log):
with open(file_path, 'a') as file:
file.write('\n'.join(input_log) + '\n')
def parse_input_record(record):
parsed_record = {}
parts = record.split(',')
for part in parts:
key, value = map(str.strip, part.split(':'))
parsed_record[key] = value
return parsed_record
layout = [
[sg.Text('請選擇過去的五筆紀錄')],[sg.Button('填入')],
[sg.DropDown(values=read_input_log(input_log_file), key='saved_inputs')],
[sg.Text('公司代號(以逗號分隔)'), sg.InputText(key='company_ids')],
[sg.Text('年份範圍(使用範圍符號 "-")'), sg.InputText(key='year_range')],
[sg.Text('月份範圍(使用範圍符號 "-")'), sg.InputText(key='month_range')],
[sg.Button('確認'), sg.Button('離開並儲存搜尋紀錄', key='leave')],
[sg.Table(values=[], headings=['公司代號', '公司名稱', '當月營收', '上月營收', '去年當月營收', '上月比較增減(%)', '去年同月增減(%)', '月份'],
auto_size_columns=False, justification='right', key='table',
col_widths=[15, 30, 15, 15, 15, 20, 20, 15],
row_height=30, display_row_numbers=False, bind_return_key=True, enable_events=True, num_rows=20)],
]
window = sg.Window('公司資料查詢工具', layout, resizable=True, finalize=True)
- 介面呈現

2.產生折線圖
- 表格對於若我同時搜尋多家公司或多個年度,要去比較時其實不太方便,所以我額外產生三個按鈕來產生折線圖,分別是 不同公司營收圖、歷年營收比較 、營收增減%圖
- 先在layout增加按鈕
- 不同公司營收圖 、營收增減%圖
這兩張圖的產生邏輯相同,只是抓取不同欄位,故我一起說明,
- 取得表格資料: 從界面中的表格元素中取得資料。
- 資料處理: 將表格資料按照公司代號('公司代號')進行分組(使用 groupby 函式),並按照年份月份('月份')進行排序。
- 製作繪圖所需的資料: 創建一個字典 plot_data,用於存儲每家公司的月份和營收數據。
- 繪製折線圖: 對於每家公司,將其營收數據加入 plot_data 字典中,然後使用 plt.plot 函式繪製折線圖。
- 將
'營收'
替換程'營收增減(%)'
就可以完成營收增減%圖

- 歷年營收比較
- 這張圖比較不一樣,他是只會看一家公司的數據,但可以在月份的軸上看到多個月的比較,可以去比較同時期去年度的表現,
- 所以他是透過year_data去分類
- 過濾選擇公司的資料: 從整體資料中篩選出選擇公司的相關資料。
- 製作繪圖所需的資料: 創建一個字典 years_data,用於存儲該公司不同年度的月份和營收數據。
- 繪製折線圖: 對於每年份,將其營收數據加入 years_data 字典中,然後使用 plt.plot 函式繪製折線圖。
- 成果!
