Python爬蟲教學| 財經數據|台灣貨幣總計數 M1B & M2

  • Post author:
  • Reading time:7 mins read

全球經濟面臨空頭襲擊,資金行情被美國聯準會升息潮打擊,很多人說 2022 是總經盤, 牛市階段,個股棒棒開花,投資人反倒覺得總經不夠靈敏,而現今熊市時刻,覆巢之下無完卵 ,投資人開始注意總經的影響力。市面上有不錯的總經平台,如「財經M平方」提供數據圖表,可惜沒提供財經數據API的服務,若要使用總經數據,還是得自己想辦法,所幸有Python爬蟲可以幫我們解決需求。貨幣總計數M1B和M2象徵「流動資金」與「保守資金」的消長,或能幫助資金行情判斷,這篇文章將示範如何爬取M1B和M2的年增率。

財經數據資料源

貨幣總計數的資料最源頭來自台灣中央銀行的新聞稿,每月23-30號間發布「上月金融狀況」,頁內有M1B和M2的年增率的表格資料。然而新聞稿區的早期資料不是那麼完全,網頁格式也變動多次,如果要在此爬蟲所有歷史資料,並非最佳解。

截圖 2022 11 03 上午8.25.25
央行每月金融情況新聞稿


所幸 行政院主計處 也有M1B和M2的數據,而且看來是可以一次抓下JS圖表內的所有數據,會比央行省事省力的許多。然而不幸的是此資料並非完美,現在都已經2022/11/3了,主計處資料還停在8月數據,但中央銀行早在10/24就發布了,怎麼更新同步基調差那麼多?如果是10/31前公佈都還好,拖到11月就真的太慢了。
所以我們需要兩個Python爬蟲,一個爬主計處的財經數據歷史資料。一個爬中央銀行當月的貨幣總計數,作為之後更新最新資料使用。

主計處Python爬蟲

爬蟲開發的第一步是觀察網頁結構,如果資料是以html的table來呈現,那是用pandas的read_html,就非常好解析,據經驗,80%情況都是如此。然而如果不是table,就比較麻煩,若財經數據有直接渲染在網頁,可以用 Beatifulsoup 解析整份 html 檔,再定位標籤抓資料。
可以看到 行政院主計處 的最新M1B數據是7.55,我們可以在Chrome瀏覽器按右鍵選擇檢查,搜尋「7.55」放在哪邊?之後可以發現7.55出現在4個地方,然而table內只有一筆資料,由於我們要抓到歷史資料是放在圖表,圖表資料一般都放在<scripttype type=”text/javascript”>標籤裡的變數,經過搜尋發現我們要把chartValue變數內的資料解析出來。

截圖 2022 11 03 上午8.26.47
行政院主計處M1B年增率
截圖 2022 11 03 上午8.38.35

Python爬蟲程式範例

流程和細節看程式註解,重點在BeautifulSoup網頁解析,和pandas如何產生目標時間序列。下列幾個要熟悉的工具說明。

from bs4 import BeautifulSoup
import pandas as pd
import requests
from datetime import datetime


def crawl_history_from_dgbas():
    # 抓下網頁回傳資料
    response = requests.get('https://www.dgbas.gov.tw/point.asp?index=10')
    # 解析網頁
    parsed_file = BeautifulSoup(response.text)
    # 找出javascript區塊
    js_text = parsed_file.find_all('script', type="text/javascript")
    # 抓財經數據定位,資料為餘第3個javascript
    data = js_text[3].string

    # 文字資料定位,擷取數據部分,將js的日期型態Date.UTC取代成空白
    m1b = data[data.index('chartValue[6]') + len('chartValue[6]='):data.index(';\r\nchartValue[7]')].replace(
        'Date.UTC', '')
    # 將文字轉陣列
    eval_m1b = eval(m1b)
    # 取出數值,迴圈內d變數已被轉成空白,無意義
    m1b_values = [v for d, v in eval_m1b]

    # 重複上述動作,觀察chartValue內陣列定位,抓出M2數據
    m2 = data[data.index('chartValue[7]') + len('chartValue[7]='):data.index(';\r\nchartValue[8]')].replace(
        'Date.UTC', '')
    eval_m2 = eval(m2)
    m2_values = [v for d, v in eval_m2]
    
    # 日期處理,由於無法抓到即時公告日期,且央行公告日前每月不定,都在每月25號左右公告上月數據,為作業方便,目標將日期設為每月最後一天
    # 取出陣列內起始日期、結束日期
    start_date = eval_m1b[0][0]
    end_date = eval_m1b[-1][0]
    # 將日期格式轉為 pandas date_range 的參數格式,產生每月日期序列
    start = f'{start_date[0]}-{start_date[1]}-{start_date[2]}'
    end = f'{end_date[0]}-{end_date[1] + 1}-{end_date[2]}'
    # 日期序列為每月1日,為產生本月底公告去年數據的效果,使用tseries.offsets將日期後推
    dates = pd.date_range(start, end, freq='M') + pd.tseries.offsets.MonthEnd(2)
    
    # 產生m1b與m2數據,將數據併表
    m1b_df = pd.DataFrame({'stock_id': '貨幣總計數M1B', 'date': dates, '年增率(%)': m1b_values})
    m2_df = pd.DataFrame({'stock_id': '貨幣總計數M2', 'date': dates, '年增率(%)': m2_values})
    concat_df = pd.concat([m1b_df, m2_df])
    concat_df = concat_df.set_index(['stock_id', 'date'])
    return concat_df

Python爬蟲輸出結果

截圖 2022 11 03 上午9.08.26

中央銀行Python爬蟲

這個爬蟲要分兩步驟,首先由於每月金融情況新聞稿的連結沒有規律,所以要先解析最新消息的>新聞稿的首頁,取出近月新聞稿的超連結,再將連結傳到 python requests 取得表格數據,之後再將資料稍微整理成前面主計處爬蟲的資料格式。
另外要注意若每月25號前就執行此爬蟲,可能會有當月資料還沒公告的問題,所以要加上例外狀況處理,回傳一個空的dataframe。

截圖 2022 11 03 上午9.24.01

Python爬蟲程式範例

def central_bank_crawl():
    
    # 資料目標日期,轉成民國型態的上月日期
    now = datetime.now()
    year = now.year - 1911
    month = (now.month + 10) % 12 + 1
    if month == 12:
        year -= 1
    
    # 解析出最新消息內近月金融情況新聞稿的超連結
    menu_response = requests.get('https://www.cbc.gov.tw/tw/lp-302-1.html')
    parsed_file = BeautifulSoup(menu_response.text)
    text = parsed_file.find('a', title=f"{year}年{month}月金融情況")

    # 沒資料則回傳空表
    if text is None:
        return pd.DataFrame()

    # 取出超連結
    href = text['href']
    
    # read_html 解析表格數據
    report_response = requests.get(f'https://www.cbc.gov.tw/{href}')
    report_df = pd.read_html(report_response.text)[0]
    report_df.columns = report_df.columns.get_level_values(1)
    report_df = report_df.iloc[:, :3]
    report_df = report_df.rename(columns={'項 目': 'stock_id', '年增率': '年增率(%)'})
    report_df = report_df[['stock_id', '年增率(%)']]
    report_df['date'] = datetime(now.year, now.month, 1) + pd.tseries.offsets.MonthEnd(1)
    report_df = report_df.set_index(['stock_id', 'date'])
    return report_df

結論

colab程式範例
這個爬蟲和證交所那類好爬的表格與穩定資料相比,有一些要注意的坑,處理上也比較多層,所以特別記錄一下。行政院主計處和央行還有許多總經數據,如果你有需求,可以自己用上述範例練習抓抓看,或直接使用 FinLab資料庫 來抓喔。

如果你對爬蟲想知道更多,可參考我們其他教學文章

超簡單台股每日爬蟲教學
超簡單用python抓取每月營收
三大法人爬蟲:Python實作教學
python上櫃資料爬蟲輕鬆做
財報爬蟲超簡單 – 用Python一次抓綜合損益、資產負債、營利分析

Ben

Python 軟體工程師與量化策略研究員。 鑽研資料工程、網頁後端、資料視覺化、量化交易策略開發。 投資主力在台股市場,量化策略為主、質化分析為輔,追求人機攜做最佳化。逐步將觸角延伸到總經、美股、加密貨幣,朝更全方位的交易人邁進。