はじめに
株式投資の分析やポートフォリオ作成において、「日経平均株価(日経225)の構成銘柄リストが欲しい!」と思う場面は多いですよね。
証券会社のサイトなど色々な場所に一覧はありますが、プログラムから直接扱いやすいデータフォーマット(CSVなど)でサクッと取得したい場合、Wikipediaの日経平均株価ページからスクレイピングしてくるのが一番手軽です。
今回は、Pythonを使って以下のステップを全自動化するスクリプトを作成しました。
- Wikipediaから「日経225構成銘柄」と「対象業界(セクター)」を取得
- 取得した銘柄リストを使って、Yahoo Finance(
yfinance)から過去1年分の月次株価を一括取得 - 扱いやすいCSV形式で保存する
Wikipediaスクレイピングの注意点(マナー)
実装に入る前に、Wikipediaをスクレイピングする際の重要なマナーについて触れておきます。
Wikipediaの運営元(Wikimedia財団)は、自動化プログラムからのアクセスに対して「User-Agent を設定して誰がアクセスしているか明示すること」を求めています。
Pythonの requests や pandas.read_html をデフォルトのまま使うと、403 Forbidden エラーで弾かれることがあります。そのため、リクエストヘッダに必ず User-Agent を設定しましょう。
また、今回は1ページのみのアクセスですが、ループで大量のページにアクセスする場合は time.sleep() などを入れてサーバーに負荷をかけない配慮が必要です。
準備と実行環境
以下のライブラリを使用します。インストールしていない場合は pip で入れておいてください。
pip install pandas requests beautifulsoup4 lxml yfinance
-
pandas,lxml: HTMLのテーブル解析やデータ整形用 -
requests,beautifulsoup4: HTML取得とDOM解析用 -
yfinance: Yahoo Financeから株価履歴を取得するため
実装コード
それでは、一気にデータを取得・整形してCSVに書き出すコードです。
import pandas as pd
import yfinance as yf
import requests
from bs4 import BeautifulSoup
import re
from io import StringIO
def get_nikkei_history():
print("1. Wikipediaから日経225の構成銘柄と対象業界を取得中...")
url = "https://ja.wikipedia.org/wiki/%E6%97%A5%E7%B5%8C%E5%B9%B3%E5%9D%87%E6%A0%AA%E4%BE%A1"
# 403 Forbiddenエラー回避とマナーのためのUser-Agent設定
headers = {'User-Agent': 'Mozilla/5.0'}
response = requests.get(url, headers=headers)
soup = BeautifulSoup(response.content, "html.parser")
data = []
current_industry = None
# Wikipediaページ内の見出し(h3)とテーブル(table)を順番に解析
# h3タグに「食品(11銘柄)」のように業界名が書かれているため、それを拾いながら下の表を見る
for element in soup.find_all(['h3', 'table']):
if element.name == 'h3':
text = element.text.strip()
if '銘柄)' in text:
# "食品(10銘柄)" -> "食品" に整形
current_industry = re.sub(r'(.*', '', text).strip()
elif element.name == 'table' and current_industry:
try:
# StringIOでラップしてpandasの警告を回避
dfs = pd.read_html(StringIO(str(element)))
df = dfs[0]
if '証券コード' in df.columns and '銘柄' in df.columns:
for _, row in df.iterrows():
data.append({
'証券コード': row['証券コード'],
'対象業界': current_industry,
'銘柄': row['銘柄']
})
except Exception:
pass
result_df = pd.DataFrame(data)
# 通し番号(1〜225)を先頭に追加
result_df.insert(0, '通し番号', range(1, len(result_df) + 1))
print(f"-> {len(result_df)} 銘柄情報を取得しました。\n")
print("2. Yahoo Financeから過去1年の月次株価を取得中...")
# 日本株はコード末尾に ".T" が必要
tickers = [f"{code}.T" for code in result_df['証券コード']]
ticker_str = " ".join(tickers)
# period="1y", interval="1mo" で過去1年分の月次データを一括ダウンロード
stock_data = yf.download(ticker_str, period="1y", interval="1mo", progress=False)
open_prices = stock_data['Open']
# 日付インデックスを "YYYY-MM" 形式にフォーマット
months = [dt.strftime('%Y-%m') for dt in open_prices.index]
open_prices.index = months
# 各月のデータを列として追加
for month in months:
price_dict = open_prices.loc[month].to_dict()
prices = []
for code in result_df['証券コード']:
ticker = f"{code}.T"
price_val = price_dict.get(ticker, pd.NA)
# データが存在しない場合はハイフンハイフン、ある場合は小数点1桁で丸める
prices.append("-" if pd.isna(price_val) else round(price_val, 1))
result_df[month] = prices
print("-> 株価データの取得と結合が完了しました。\n")
# UTF-8 with BOMでエクセルでも文字化けしないように保存
output_filename = "nikkei225_1y_history.csv"
result_df.to_csv(output_filename, index=False, encoding="utf-8-sig")
print(f"『{output_filename}』 として保存しました!")
if __name__ == "__main__":
get_nikkei_history()
コードのポイント解説
1. BeautifulSoup と pandas の合わせ技
Wikipediaの日経225ページは、証券コードと銘柄名のテーブルが業種(セクター)ごとに分かれて配置されています。
単に pandas.read_html() ですべてのテーブルを取得してしまうと、「どの銘柄がどの業種なのか」という情報が抜け落ちてしまいます。
そこで、BeautifulSoup を使ってHTMLツリーを上から順に走査し、<h3>タグを見つけたら業種名を一時変数に保存、直後の <table>タグを見つけたらその業種名を紐付けながら pandas.read_html() でデータ化する、という少し工夫したロジックを入れています。
2. yfinance で一括ダウンロード
yfinance の素晴らしいところは、複数のティッカーシンボル(證券コード)をスペース区切りで渡すだけで、非同期的に一括でデータを取ってきてくれる点です。
forループで1銘柄ずつリクエストを送ると膨大な時間がかかってしまいますが、yf.download("7203.T 9984.T ...") のように渡せば数十秒で225銘柄の過去データが手に入ります。
実行結果 (CSVの出力イメージ)
スクリプトを実行すると、同階層に nikkei225_1y_history.csv が作成されます。Excelなどで開くと以下のようなデータ構造になります。
| 通し番号 | 証券コード | 対象業界 | 銘柄 | 2025-04 | 2025-05 | ... | 2026-03 |
|---|---|---|---|---|---|---|---|
| 1 | 2002 | 食品 | 日清製粉グループ本社 | 2000.5 | 2050.0 | ... | 2100.0 |
| 2 | 2269 | 食品 | 明治ホールディングス | 3500.0 | 3600.0 | ... | 3550.0 |
| ... | ... | ... | ... | ... | ... | ... | ... |
まとめ
Wikipediaのようなよく整理された公開情報と、yfinance のような強力なAPIを組み合わせることで、実用的な金融データセットを数秒で構築することができました。
スクレイピングのマナー(User-Agent)にだけ気をつければ、非常に強力な武器になるのでぜひ試してみてください。