1. はじめに
「個人で株価を分析するちょっとしたWebアプリを作りたい!」
そう思って、React + FastAPI + Dockerで構築しようとしたら、yfinanceがすぐにアクセス過多のエラーが発生しました。
(時間空けながらアクセスはしても発生)
ただGoogle Colabで実施したら、時間空けながらyfinanceで実施しても、問題なく取得できました。
原因を調査すると、以下のようなことが考えられそうでした。
- アクセスはIPごとに制限される
- https://github.com/ranaroussi/yfinance/issues/2422?utm_source=chatgpt.com
- 中間者(プロキシ、VPN、クラウド)を経由したColab等では、IPが頻繁に変わったりホワイトリスト化されていてエラー回避できている可能性がある
- User‑Agent 等から bot と認識される
そこで私は、Google Colab × Streamlit の組み合わせでWebアプリケーションが出来ないかを検討したところngrokを利用することで、Webアプリケーションが構築できるということを見つけて、実際に確認してみました。
2. アーキテクチャと構成
構成図は以下の通りです。
[ Google Colab ] → Streamlit (port 8501) → ngrok tunnel → [ User browser ]
↑
yfinance(米/日株)
使用技術
技術 | 用途 |
---|---|
Streamlit | Web UIの描画 |
yfinance | 株価データ & ニュースの取得 |
mplfinance | ローソク足チャートの描画 |
pyngrok | Colab環境を外部公開 |
ngrokとは?
Colabで立てたStreamlitサーバーは外部からアクセスできません。
ngrokを使うと、ローカルポートをパブリックURLとして中継できるようになります。
3. ソース解説
データ取得層
def fetch_price(ticker: str):
df = yf.download(ticker, period="1mo", interval="1d", group_by="ticker")
df = flatten_columns(df, ticker)
df = ensure_datetime_index(df)
if {"Open", "High", "Low", "Close", "Volume"}.issubset(df.columns):
return df.dropna()
return None
def fetch_company_name(ticker: str):
info = yf.Ticker(ticker).info
return info.get("shortName") or info.get("longName") or ticker
データ整形層
def flatten_columns(df, ticker):
if isinstance(df.columns, pd.MultiIndex):
lvl0 = df.columns.get_level_values(0)
if "Price" in lvl0:
return df.droplevel(0, axis=1)
elif ticker in lvl0:
return df.xs(ticker, axis=1, level=0)
return df
def ensure_datetime_index(df):
if not isinstance(df.index, pd.DatetimeIndex):
df.index = pd.to_datetime(df.index, errors="coerce")
return df
ニュース解析層
def parse_news(raw):
parsed = []
for n in raw:
title = n.get("title") or n.get("headline") or n.get("content", {}).get("title")
link = n.get("link") or n.get("url") or n.get("canonicalUrl", {}).get("url") or n.get("content", {}).get("clickThroughUrl", {}).get("url")
ts = n.get("providerPublishTime") or n.get("pubDate")
time_str = datetime.fromtimestamp(ts, tz=timezone.utc).strftime("%Y-%m-%d %H:%M") if isinstance(ts, (int, float)) else ""
if title:
parsed.append({"title": title, "link": link or "", "time": time_str})
return parsed
UI描画層
def render_chart(df, title):
fig, _ = mpf.plot(df, type="candle", volume=True, style="yahoo", returnfig=True)
st.subheader(title)
st.pyplot(fig)
def render_news_section(ticker, company):
if st.button(f"{company} のニュースを表示 / 隠す"):
st.session_state.show_news = not st.session_state.show_news
if st.session_state.show_news:
news = parse_news(getattr(yf.Ticker(ticker), "news", [])[:5])
st.subheader(f"{company} 最新ニュース")
for n in news:
st.markdown(f"- {n['time']} | [{n['title']}]({n['link']})" if n["link"] else f"- {n['time']} | {n['title']}")
実際の画面のイメージはこちらです。
初期画面
検索ボタンクリック時
ニュース表示ボタンクリック時
上記のようにGoogle Colabを利用して動的なアプリケーションを構築できました。
また、ngrokのtunnelを構築するのは以下のようなソースで問題ありません。
from pyngrok import ngrok
import threading, os, time
# 認証トークンを最初に設定(1回だけでOK)
ngrok.set_auth_token(AUTH-TOKEN)
# Streamlit実行
def run():
os.system("streamlit run app.py")
threading.Thread(target=run).start()
# 起動まで少し待機してから公開
time.sleep(5)
public_url = ngrok.connect(addr="8501", proto="http")
print(f"公開URL: {public_url}")
また、既存トンネルがあると競合してしまい、エラーが発生するので、明示的に削除する必要があります。
ngrok.kill()
4. メリットとデメリット
✅ メリット | ⚠️ デメリット |
---|---|
Colabだけで完結し、環境構築が不要 | セッション切れでアプリがリセットされる |
yfinance が安定して使える |
ngrok トンネルURLが毎回変わる |
SSLや証明書エラーに悩まされない | 本格運用には向かない(あくまで試作・個人用) |
Streamlitで高速プロトタイピング可能 | Web UIはStreamlitの制約内に限られる |
5. おわりに
Colabとngrokを組み合わせれば、Python一つで株価情報とニュースを確認できるWebアプリを簡単に作れます。
Colabベースのこの構成は最小構成で最大の成果を得る手段になります。
正直個人的にはフロントエンドとバックエンドを分離できないため、とても開発しにくいと思っていますがw、 簡単に動的画面で分析したい場合はとても良いと思いました!