TL;DR
- クラウド CI(GitHub Actions など)から 無料で日本株の終値 を取りたいなら、現状ほぼ唯一の現実解は
stooq.comの apikey 経由 CSV エンドポイント だった。 - yfinance はローカル PC では問題なく動くが、Actions の共有 IP からは
YFRateLimitError: 429で全銘柄落ちる。 - 「stooq は素で叩ける」と書かれた古い記事はもう通用しない。2026 年時点で素叩きは apikey 取得案内テキストしか返してこない。
- apikey は無料・登録不要・captcha のみで取得できるが、IP や利用回数で 失効する ので、失効を検知する CSV パースを書いておくこと。
背景:何を作ろうとしていたか
平日 17:00 JST に日本株の終値を取って、ある基準日との差分を自分宛にメールする日次バッチを作っていた。要件はシンプル。
- 対象は東証の数銘柄。
- スケジューラは GitHub Actions の
schedulecron。 - 言語は Python。
- 株価データソースは無料・登録不要なものを優先したい。
ローカル PC では普通に動くものを作って、Actions に載せ替えた瞬間に取得が全滅した、というのが本記事の出発点。
試行 1:yfinance — クラウド IP では使えなかった
最初に選んだのは yfinance。Python では事実上の標準ライブラリで、Yahoo Finance 経由でほぼ何でも取れる。ローカル開発中はこれで一切問題なく動いていた。
import yfinance as yf
t = yf.Ticker("7203.T")
print(t.fast_info["last_price"])
これを GitHub Actions に載せた途端、全銘柄でこういうエラーが出るようになった。
yfinance.exceptions.YFRateLimitError: Too Many Requests. Rate limited. Try after a while.
fast_info でも Ticker.history(period="5d") でも同じ。リトライしても 1 分待っても駄目。
なぜローカルでは動いてクラウドだと落ちるか
GitHub Actions の Runner IP は AWS / Azure 帯から払い出される共有 IP で、世界中の bot がここを通って Yahoo Finance を叩いている。Yahoo 側のレート制限・bot 弾きは IP 単位で効くので、自分一人の使用量がほぼゼロでも 同じ IP を共有している他人のせいで 429 を食らう。
これは yfinance のせいでも自分のコードのせいでもなく、構造的にどうにもならない。よって クラウド CI からの定期実行用途では yfinance は使えない と結論。
試行 2:stooq.com の素叩き CSV — 2026 年は apikey 必須化済み
次の候補が stooq.com。「日本株 CSV 無料」で検索するとほぼ筆頭に出てくる Web サービスで、東証銘柄も普通にカバーしている。古い記事には「URL を叩くだけで CSV が降ってくる」と書いてある。
試したのはこういう URL(7203.jp はトヨタ)。
https://stooq.com/q/d/l/?s=7203.jp&i=d
Actions からも自宅回線からも実行してみたが、CSV は降ってこず、こういうテキストが返ってくる。
Get your apikey: https://stooq.com/q/d/?s=7203.jp&get_apikey
Content-Type も text/csv ではなく text/plain で、200 OK で返してくる。csv.reader に食わせるとヘッダーらしき 1 行を読んで終わるので、コード上は 「謎の空 CSV を読んだ」状態 に見える。これが地味にデバッグを難しくしていた。
要点はひとつ。
2026 年時点で stooq の CSV エンドポイントは apikey が必須化されている。
少し古い解説記事はそろってこの仕様変更を反映していないので、コピペで動かない。
試行 3:stooq.com の apikey 経由 — これが現状の現実解
apikey は無料で取れる。手順はこれだけ。
- ブラウザで
https://stooq.com/q/d/?s=7203.jp&get_apikeyを開く(シンボルは何でもいい)。 - captcha を解く。
- 16 桁程度の apikey 文字列が表示される。コピーする。
メール登録もアカウント作成も不要。ただし IP や利用回数で失効する ので、失効したら同じ URL を踏み直して新しい apikey に差し替える運用になる。
動くエンドポイントは apikey クエリを足すだけ。
https://stooq.com/q/d/l/?s=7203.jp&i=d&apikey=<YOUR_APIKEY>
Python での最小実装はこのくらい。標準ライブラリだけで完結する。
import csv, io, os
from urllib.request import Request, urlopen
URL = "https://stooq.com/q/d/l/?s={symbol}&i=d&apikey={apikey}"
def fetch_close(symbol: str) -> float | None:
url = URL.format(symbol=symbol, apikey=os.environ["STOOQ_APIKEY"])
with urlopen(Request(url, headers={"User-Agent": "myapp"}), timeout=15) as r:
text = r.read().decode("utf-8")
rows = list(csv.DictReader(io.StringIO(text)))
if not rows:
return None # apikey 失効 / シンボル不正の可能性
close = next((v for k, v in rows[-1].items() if k.lower() == "close"), None)
if not close or close == "N/D":
return None
return float(close)
GitHub Actions に載せるときは STOOQ_APIKEY を Secrets に登録して env: で渡すだけ。コードは Secrets を print しないように気をつけること。
比較表
| 項目 | yfinance | stooq 素叩き | stooq apikey | Alpha Vantage |
|---|---|---|---|---|
| 登録 | 不要 | 不要 | 不要 (captcha のみ) | 必要 (メール) |
| 無料利用 | ◯ | ✕ (2026 現在) | ◯ | ◯ (5 req/min・25 req/day) |
| クラウド CI から動くか | ✕ (429) | ✕ | ◯ | ◯ |
| 日本株(東証) | ◯ | ◯ | ◯ | △ (シンボル形式要確認) |
| データ形式 | Python オブジェクト | CSV | CSV | JSON |
| ヒストリカル | 数十年 | 数十年 | 数十年 | 20 年程度 |
stooq.com を使うときの注意点
1. apikey は失効する
これが運用上一番ハマりやすい。失効すると CSV ではなく例の Get your apikey: テキストが返ってくるので、**「200 OK だけど CSV が空」**という挙動になる。csv.DictReader で 0 行になったケースをエラーとして扱い、本文先頭 100 文字くらいを preview として一緒にログに出すようにしておくと、失効時に一目で分かる。
preview = text[:160].replace("\r", "").replace("\n", " | ")
# rows が空なら preview をログに出してアラート
2. シンボル形式は <銘柄コード>.jp(小文字)
東証は 7203.jp(トヨタ)形式。Yahoo Finance 系の .T(7203.T)ではない。大文字 .JP を受け付けるかは挙動が安定しないので 小文字固定 が安全。米株はそのままティッカー(AAPL など)。
3. CSV ヘッダーは大文字始まり、ただし揺らぎ対策を
正常系のヘッダーは Date,Open,High,Low,Close,Volume。ただし将来仕様が変わる可能性、空行や BOM が混ざるケースを考慮して、キー名は lower() で比較しておくのが安全。
4. 本番停止リスクの備えは別ソースを用意しておく
stooq が apikey 制度をさらに変えたり、無料枠を絞ったりした瞬間に詰む。Alpha Vantage の function=GLOBAL_QUOTE を apikey 込みで叩く実装に切り替えられるよう、fetch_close() 相当の関数を独立させて差し替え可能にしておくと、復旧コストが 30 分で済む。
5. 利用規約は一度読んでおく
無料で叩ける = 何をしてもいい、ではない。商用利用・再配布・大量取得は stooq の Terms 次第なので、自分用の日次バッチを超える使い方をする前に必ず確認すること。
結論:用途別の使い分け
| 用途 | おすすめ |
|---|---|
| ローカル開発・notebook 検証 | yfinance で十分。手軽さが圧倒的。 |
| GitHub Actions / Vercel / Cloudflare Workers から定期実行 | stooq.com の apikey 経由。コード変更最小で安定して動く。 |
| 商用・SLA が必要 | 有料 API(Alpha Vantage 有料プラン / Polygon / J-Quants 等)。 |
「個人で日次バッチを作りたい」が目的なら、ローカル開発時に yfinance で書いておいて、クラウドに載せる段階で stooq apikey に差し替えるのが一番ラクだった、というのが今回の結論。コード変更は URL に &apikey=... を 1 行足して、CSV 末尾行の Close を読むパーサーを書くだけで済む。

コメント