LoginSignup
12

More than 1 year has passed since last update.

posted at

BeautifulSoupで全上場銘柄の過去の株価を20年分取得してみた

最近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))

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
12