GitHub Actions から日本株の終値を取りたいなら stooq.com(apikey 経由)一択だった話

プログラミング関連

TL;DR

  • クラウド CI(GitHub Actions など)から 無料で日本株の終値 を取りたいなら、現状ほぼ唯一の現実解は stooq.comapikey 経由 CSV エンドポイント だった。
  • yfinance はローカル PC では問題なく動くが、Actions の共有 IP からは YFRateLimitError: 429 で全銘柄落ちる。
  • 「stooq は素で叩ける」と書かれた古い記事はもう通用しない。2026 年時点で素叩きは apikey 取得案内テキストしか返してこない
  • apikey は無料・登録不要・captcha のみで取得できるが、IP や利用回数で 失効する ので、失効を検知する CSV パースを書いておくこと。

背景:何を作ろうとしていたか

平日 17:00 JST に日本株の終値を取って、ある基準日との差分を自分宛にメールする日次バッチを作っていた。要件はシンプル。

  • 対象は東証の数銘柄。
  • スケジューラは GitHub Actions の schedule cron。
  • 言語は 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 は無料で取れる。手順はこれだけ。

  1. ブラウザで https://stooq.com/q/d/?s=7203.jp&get_apikey を開く(シンボルは何でもいい)。
  2. captcha を解く。
  3. 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 系の .T7203.T)ではない。大文字 .JP を受け付けるかは挙動が安定しないので 小文字固定 が安全。米株はそのままティッカー(AAPL など)。

3. CSV ヘッダーは大文字始まり、ただし揺らぎ対策を

正常系のヘッダーは Date,Open,High,Low,Close,Volume。ただし将来仕様が変わる可能性、空行や BOM が混ざるケースを考慮して、キー名は lower() で比較しておくのが安全。

4. 本番停止リスクの備えは別ソースを用意しておく

stooq が apikey 制度をさらに変えたり、無料枠を絞ったりした瞬間に詰む。Alpha Vantage の function=GLOBAL_QUOTEapikey 込みで叩く実装に切り替えられるよう、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 を読むパーサーを書くだけで済む。

コメント

タイトルとURLをコピーしました