電腦關機也能跑!用 GitHub Actions 免費託管你的股票監控機器人
各位好!
歡迎來到我們「股票監控機器人」系列的最終章。
回顧一下我們做到了什麼: 1. 用 Playwright 抓取了元大官網的 0050 成分股資料。 2. 用 Python 程式邏輯 清洗並整理了資料。 3. 用 Discord Webhook 將精簡的報表推送到你的手機。
現在這套系統很完美,但它還有一個最大的缺點:你的電腦必須開著,程式才會跑。 如果你筆電蓋起來,或是出門旅遊,這隻爬蟲就掛了。這不符合我們「懶人自動化」的極致精神!
今天我們要用 GitHub Actions 來解決這個問題。它提供每個月 2000 分鐘的免費額度,對於我們這種每天跑幾秒鐘的小爬蟲來說,根本用不完!
為什麼要用 GitHub Actions?
- 完全免費:對於個人專案或輕量級自動化任務,幾乎不需要花任何費用。
- 無需伺服器:你不需要租用 VPS 或學習複雜的雲服務。只要有 GitHub 帳號即可。
- 排程功能:內建 Cron Job 排程,可以設定每天、每週、每月固定時間自動執行。
- 穩定可靠:由 GitHub 提供的雲端環境,網路穩定,不用擔心自家網路斷線。
專案結構與程式碼準備
首先,在你的電腦上建立一個資料夾(例如 stock_monitor),然後將以下程式碼依序放入對應的檔案中。
1. 核心程式碼:main.py
這個檔案包含爬蟲、資料處理和發送 Discord 訊息的所有邏輯。注意 DISCORD_WEBHOOK_URL 已經改成從環境變數讀取,這是安全性的考量。
# main.py
import os
import requests
import time
from playwright.sync_api import Playwright, sync_playwright
# 從環境變數讀取 Discord Webhook 網址
# 在本機測試時,你可以在終端機設定環境變數,或暫時貼上網址測試(上傳 GitHub 前記得刪掉!)
DISCORD_WEBHOOK_URL = os.environ.get("DISCORD_WEBHOOK_URL")
def send_discord_message(content):
"""發送訊息到 Discord"""
if not DISCORD_WEBHOOK_URL:
print("錯誤: 未設定 DISCORD_WEBHOOK_URL 環境變數,無法發送訊息。")
# 為了避免在 CI/CD 環境因為這個錯誤而直接中斷,這裡可以選擇 return 或 raise
# 這裡選擇 return,讓 GitHub Actions 的 Job 能夠完成,但會有錯誤訊息
return
data = {
"content": content,
"username": "0050 監控機器人" # 你可以隨意改名
}
try:
response = requests.post(DISCORD_WEBHOOK_URL, json=data)
if response.status_code == 204: # 204 No Content 代表成功發送
print("訊息已成功發送至 Discord")
else:
print(f"發送失敗: HTTP {response.status_code} - {response.text}")
except Exception as e:
print(f"發送時發生錯誤: {e}")
def run(playwright: Playwright) -> None:
print("啟動爬蟲...")
# 啟動瀏覽器 (在 GitHub Actions 上必須是 headless=True)
browser = playwright.chromium.launch(headless=True)
page = browser.new_page()
try:
# 1. 前往元大官網
print("前往元大官網...")
page.goto("https://www.yuantaetfs.com/product/detail/0050/ratio")
# 2. 處理彈窗 (點擊確定)
# 使用 try/except 處理彈窗,如果沒出現也不會報錯
try:
btn = page.get_by_role("button", name="確定")
if btn.is_visible(timeout=5000):
btn.click()
else:
print("Info:彈窗未出現跳過。")
except Exception:
print("Info: 彈窗處理失敗或未出現,繼續執行。")
print("點擊展開按鈕...")
page.get_by_text("展開").click()
# 4. 等待表格內容出現後,抓取表格文字
print("抓取表格資料...")
page.wait_for_selector("div:nth-child(3) > .each_table")
raw_text = page.locator("div:nth-child(3) > .each_table").all_inner_texts()[0]
print("正在整理報表數據...")
lines = raw_text.strip().split('\n')
# 準備 Markdown 格式的 Discord 訊息
message_lines = [
f"**0050 前十大成分股權重監控**",
f"**更新時間**: {time.strftime('%Y-%m-%d %H:%M:%S')}",
"```text" # Discord 的程式碼區塊,用於等寬字體排版
]
# 表頭
message_lines.append(f"{'代號':<6} {'名稱':<6} {'權重(%)':>8}")
message_lines.append("-" * 24) # 分隔線
count = 0
for line in lines:
parts = line.split()
# 過濾邏輯:只要有 4 個欄位,且第一個欄位(代碼)是純數字
if len(parts) == 4 and parts[0].isdigit():
code, name, _, weight = parts
# 格式化字串:<6 靠左對齊佔 6 格,>8 靠右對齊佔 8 格
message_lines.append(f"{code:<6} {name:<6} {weight:>8}")
count += 1
if count >= 10: # 只取前 10 名
break
message_lines.append("```") # 結束程式碼區塊
final_msg = "\n".join(message_lines)
# 發送訊息到 Discord
send_discord_message(final_msg)
except Exception as e:
print(f"爬蟲執行發生未預期錯誤: {e}")
# 如果執行失敗,也發送一個錯誤通知到 Discord
error_msg = f"**0050 監控機器人執行失敗!**\n錯誤訊息: `{e}`"
send_discord_message(error_msg)
finally:
browser.close()
print("程式結束。")
if __name__ == "__main__":
with sync_playwright() as playwright:
run(playwright)
2. 依賴清單:requirements.txt
# requirements.txt
playwright
requests
3. GitHub Actions 設定檔:.github/workflows/daily_monitor.yml
請在你的專案根目錄下建立 .github/workflows/ 資料夾,然後在裡面建立 daily_monitor.yml 檔案。
# .github/workflows/daily_monitor.yml
name: Daily Stock Monitor
on:
# 設定排程執行 (Cron Job)
schedule:
# 這是 UTC 時間!台灣是 UTC+8
# 所以如果你想在台灣時間早上 09:00 執行,要設成 UTC 01:00
# 語法: '分 時 日 月 週'
# 每天 01:00 UTC,週一到週五 (1-5) 執行
- cron: '0 1 * * 1-5'
# 允許手動點擊按鈕觸發 Workflow (方便測試用)
workflow_dispatch:
jobs:
run_scraper:
# 使用最新的 Ubuntu Linux 環境
runs-on: ubuntu-latest
steps:
# 步驟 1: 下載你的程式碼
- name: Checkout code
uses: actions/checkout@v4
# 步驟 2: 設定 Python 環境
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.12' # 建議指定一個穩定的 Python 版本
# 步驟 3: 安裝 Python 套件 (從 requirements.txt)
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
# 步驟 4: 安裝 Playwright 的瀏覽器 (這是最容易漏掉但關鍵的一步!)
# Playwright 需要真實的瀏覽器內核才能運行
- name: Install Playwright Browsers
run: |
playwright install chromium # 我們只用 Chromium,所以只安裝它
# 步驟 5: 執行爬蟲腳本
- name: Run Python Scraper Script
# 將 GitHub Secrets 中的 Webhook 網址注入到環境變數中
env:
DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }}
run: |
python main.py
部署與驗收:一步步來!
現在,你的專案資料夾應該長這樣:
stock_monitor/
├── main.py
├── requirements.txt
└── .github/
└── workflows/
└── daily_monitor.yml
請按照以下步驟進行部署:
1. 將程式碼推送到 GitHub
將你本地的 stock_monitor 資料夾初始化為 Git Repository,並將所有檔案推送到你的 GitHub 遠端儲存庫 (Repository)。
cd stock_monitor
git init
git add .
git commit -m "feat: Add 0050 stock monitor with Discord notification"
git branch -M main
git remote add origin https://github.com/你的用戶名/你的repo名稱.git
git push -u origin main
(請替換 你的用戶名 和 你的repo名稱)
2. 設定 GitHub Secrets (保護你的 Discord Webhook)
- 打開你的 GitHub 專案頁面。
- 點擊頂部的
Settings(設定)。 - 在左側選單找到
Secrets and variables,然後點擊Actions。 - 點擊右上角的
New repository secret。Name: 請填入DISCORD_WEBHOOK_URL(這個名稱必須與main.py和.yml檔案中使用的環境變數名稱完全一致)。Secret: 貼上你之前從 Discord 頻道複製的那串 Webhook 網址。
- 點擊
Add secret。
這樣,GitHub Actions 在執行時就能讀取這個網址,但它不會被公開顯示。
3. 手動觸發 Workflow 進行測試
我們需要先測試一下設定是否正確。
- 在你的 GitHub 專案頁面,點擊上方的
Actions分頁。 - 在左側的 Workflows 列表中,點擊
Daily Stock Monitor。 - 在右側你會看到一個藍色的按鈕
Run workflow,點擊它。 - 在彈出的視窗中,再次點擊綠色的
Run workflow按鈕。
這將會立即觸發一次 Job 執行。
4. 觀察執行結果並驗收
- 點擊進入正在執行的 Job,你會看到它一步步完成:
Checkout code->Set up Python->Install dependencies->Install Playwright Browsers->Run Python Scraper Script。 - 耐心等待幾分鐘,如果一切順利,你應該會看到actions出現綠勾勾
- 最重要的是:拿起你的手機,檢查你的 Discord 頻道! 你應該會收到一則來自「0050 監控機器人」的報價訊息。
如果收到了,恭喜你!你的自動化系統已經成功在雲端運行了!以後它就會根據你設定的排程(週一到週五早上九點,台灣時間)自動發送通知。
結語:你達成了一項成就!
恭喜!你現在擁有的不只是一隻爬蟲,而是一個 Serverless (無伺服器)的自動化系統。
- 你不需要付錢買 VPS。
- 你不需要整天開著電腦。
- 只要 GitHub 不倒,你的機器人就會在每個交易日的早上 9 點準時上工。
這套「Playwright + GitHub Actions + Discord Webhook」的組合技,基本上可以解決個人開發者 90% 的自動化需求。無論是監控機票價格、新書通知、還是追蹤特定商品的庫存狀態,通通都能搞定。
全系列完結!感謝大家的閱讀,快去動手打造你的懶人機器人吧!
0 留言
發表留言