Files
stocks-query/scripts/twse-pe-pbr.py
Timmy 3d14ad6e62 add monthly revenue and PE/PBR query scripts
- twse-monthly-revenue.py: fetch monthly revenue from Yahoo Finance TW via Browserless (MOPS blocks direct API)
- twse-pe-pbr.py: fetch PE ratio, PBR, dividend yield from TWSE BWIBBU API

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 10:35:21 +08:00

113 lines
3.6 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/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)