#!/usr/bin/env python3 """ 查詢 TWSE 個股本益比/股價淨值比/殖利率 用法: python3 skills/stocks-query/scripts/twse-pe-pbr.py 2330 python3 skills/stocks-query/scripts/twse-pe-pbr.py 3481 資料來源:證交所 TWSE 公開 API(個股日本益比、殖利率及股價淨值比) """ from __future__ import annotations import json import sys import urllib.request from datetime import datetime, timedelta def fetch_pe_pbr(stock_no: str, date_str: str | None = None) -> dict: """從 TWSE 抓本益比/股價淨值比,自動往前回溯最多 3 個月找到有資料的月份。""" if date_str: dates_to_try = [date_str] else: today = datetime.now() dates_to_try = [] for i in range(4): dt = today - timedelta(days=30 * i) dates_to_try.append(dt.replace(day=1).strftime("%Y%m%d")) for d in dates_to_try: url = ( f"https://www.twse.com.tw/rwd/zh/afterTrading/BWIBBU" f"?date={d}&stockNo={stock_no}&response=json" ) req = urllib.request.Request(url, headers={"User-Agent": "Mozilla/5.0"}) try: with urllib.request.urlopen(req, timeout=30) as resp: data = json.loads(resp.read().decode("utf-8", errors="replace")) except Exception: continue if data.get("stat") != "OK": continue rows = data.get("data", []) fields = data.get("fields", []) if not rows or not fields: continue # 取最新一筆 latest = rows[-1] result = {} for i, field in enumerate(fields): val = str(latest[i]).strip() if i < len(latest) else "-" result[field.strip()] = val # 附上近期歷史 result["_history"] = [] for row in rows: entry = {} for i, field in enumerate(fields): val = str(row[i]).strip() if i < len(row) else "-" entry[field.strip()] = val result["_history"].append(entry) return result raise RuntimeError(f"找不到 {stock_no} 的本益比/淨值比資料(已回溯 3 個月)") def print_summary(stock_no: str, d: dict) -> None: print(f"{stock_no}|本益比/股價淨值比摘要") date_val = d.get("日期", "-") pe = d.get("本益比", "-") pbr = d.get("股價淨值比", "-") dividend_yield = d.get("殖利率(%)", "-") fiscal_year = d.get("股利年度", "-") fiscal_quarter = d.get("財報年/季", "-") print(f"• 最新日期:{date_val}") print(f"• 本益比:{pe}") print(f"• 股價淨值比:{pbr}") if dividend_yield != "-" and "%" not in str(dividend_yield): print(f"• 殖利率:{dividend_yield}%") else: print(f"• 殖利率:{dividend_yield}") print(f"• 股利年度:{fiscal_year}") print(f"• 財報年/季:{fiscal_quarter}") # 近期趨勢 history = d.get("_history", []) if len(history) > 1: recent = history[-5:] print(f"\n近期趨勢(最近 {len(recent)} 筆):") for entry in recent: h_date = entry.get("日期", "-") h_pe = entry.get("本益比", "-") h_pbr = entry.get("股價淨值比", "-") h_dy = entry.get("殖利率(%)", "-") print(f" {h_date}|PE {h_pe}|PBR {h_pbr}|殖利率 {h_dy}%") if __name__ == "__main__": stock_no = sys.argv[1] if len(sys.argv) > 1 else "2330" try: data = fetch_pe_pbr(stock_no) print_summary(stock_no, data) except Exception as e: print(f"取得失敗:{e}", file=sys.stderr) sys.exit(1)