最近PythonのスクレイピングライブラリであるBeautifulSoupを勉強しているとかなり面白くて、何かに活用してみたくなったので、全上場銘柄の株価を取得するツールを作ってみました。取得したデータを使ってどういう分析をするかはまだ検討中ですが、色々なことができそうです。
概要
-
pandasを用いたデータの入出力
まず、こちらから東証上場銘柄一覧が記載されたCSVを保存します。私は今回ETFのデータは不要だったので事前に消しておきました。
pandasでは構造化データが扱いやすいDataFrameや、簡単にファイルの入出力ができるread_csv, to_csvメソッドが用意されており、非常に便利です。 -
requests, BeautifulSoupによるHTML取得・解析
requestsモジュールで指定したURLからHTMLを取得し、BeautifulSoupによって必要なデータを抽出します。
こちらに各銘柄の年度別株価データが載っているのですが、銘柄・年度ごとにページが分かれているので全銘柄の20年分のデータを手作業で集めるのはまず無理です。
そこで、事前に保存したコード一覧を読み込み、各コードに対して年度ごとに異なるURLにアクセスしてデータを取得します。
今回アクセスするページ数、取得するデータ量は非常に多いため、この自動化ツールを使っても私の環境では半日以上かかりました。笑
マルチプロセス等を使えばもう少し速くできるかもしれません。
ソースコード
# ライブラリをインポート
from bs4 import BeautifulSoup
import requests
import time
import os
import pandas as pd
if __name__ == '__main__':
# 開始時刻
start_time = time.time()
# 銘柄・コード一覧を取得
df_input = pd.read_csv('data_j.csv', encoding='shift_jis')
# 調べたいデータを指定
codes = df_input['コード'].to_list()
# 20年間の株価を取得する
years = range(2000, 2020)
# 各銘柄(コード)に対して
for code in codes:
df = pd.DataFrame(columns=['日付', '終値']) # 日付と終値を格納するDataFrame
row_start = 1 # 各年の最初のデータの行
flg_print = False
file_name = '' # 保存するファイル名
# 各年に対して
for year in years:
try:
# URLを取得
url = "https://kabuoji3.com/stock/" + str(code) + "/" + str(year) + "/"
# headers情報は確認くん(https://www.ugtop.com/spill.shtml)で確認
# headers = {"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.1 Safari/605.1.15 "}
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.128 Safari/537.36"
}
# HTML解析用オブジェクト
soup = BeautifulSoup(requests.get(url, headers=headers).content, 'html.parser')
# タイトルを取得
title = soup.select_one("span.jp").text
# タイトルを出力
if not flg_print:
print(title)
flg_print = True
# ファイル名を指定
file_name = '{0}.csv'.format(str(title))
# 既にファイルが存在する場合はスキップ
if os.path.exists(file_name):
break
# 株価を取り出す
all_tr = soup.find_all('tr')
# 先頭要素はヘッダなので削除
all_tr.remove(all_tr[0])
# その年のデータの最終行を取得
row_finish = row_start + len(all_tr)
# 各行に日付・終値のデータを書き込む
for i in range(row_start, row_finish):
tr = all_tr[i - row_start].find_all('td') # リスト型
date = tr[0].text # 日付
fp = tr[4].text # 終値
# DataFrameの末尾に追加
df = df.append({'日付': date, '終値': fp}, ignore_index=True)
# 次の年のデータの開始行を更新
row_start = row_finish
except:
# その年のデータが存在しなくてもエラー復帰せずに次の年のデータの取得に移る
pass
# データを保存
df.to_csv('data\\' + file_name, encoding='shift_jis', index=False)
stop_time = time.time() # 終了時刻
elapsed = stop_time - start_time # 経過時間
# 経過時間の出力
print('処理が完了しました。経過時間: {0:.1f}秒'.format(elapsed))