日本株の基礎指標(PERや配当利回り)をpythonでスクレイピングを使って取得する (1)
本記事では、日本株の基礎指標をスクレイピングで取得する手順を紹介しています。また、スクレイピング先のサイトがスクレイピングを禁止していないか確認する方法にも触れています。
[1] きっかけ
今年はコロナウィルスやアメリカ大統領選挙の影響で、株価が大きく変動しましたね。 また、「人生100年時代」や「老後資金が2,000万円必要」とか言われたりしていますから、株式投資に興味を持ち始めた人も多いのではないかと思います。
株式投資をする際に何を基準にして売買するのかは人によって違います。「ドルコスト平均法で積立」「チャートを見る」「企業の業績を見る」など色々な方法があると思います。
私はこれまで、企業の業績を見る方法は取ってきませんでしたが、取り入れてみることにしました。ただ、どうせ取り入れるなら、面倒なところはプログラミングと絡めて自動化したいなと思いました。
しかし、下記サイトを参考にさせていただいたところ、APIを使ってお手軽に取得とはいかないようです。そこで、気象データ取得の際にも活用したスクレイピングで、企業情報を取得してみます。
別記事では、pandas-datareaderを用いたAPIでの株価取得、スクレイピングでの株価取得を紹介しています。よければ、そちらもご覧になってください。
[2] 時価総額やPERなどの指標を取得
「みんなの株式」から情報を取得させてもらいます。
今回は、時価総額やPERなどの基本的な指標を取得します。JR東日本をはじめとした鉄道会社の情報を集めます。
[3] スクレピング可能か確認する
スクレイピングを禁止しているサイトも多くあります。「みんなの株式」がスクレピング可能か否かを確認します。
スクレイピング可能であったとしても、取得元のWebサイトに負荷をかけないように気をつけましょう。
[3-1] 規約を確認する
まずは規約を確認します。例えば、Yahoo!ファイナンスではスクレイピングを禁止しています。利用規約やFAQ、ヘルプを探してみましょう。
Yahoo!ファイナンスはヘルプに書かれています(2020/11/23時点)。
Yahoo!ファイナンスでは、Yahoo!ファイナンスに掲載している株価やその他のデータを、プログラム等を用いて機械的に取得する行為(スクレイピング等)について、システムに過度の負荷がかかり、安定したサービス提供に支障をきたす恐れがあることから禁止しています。
[3-2] robots.txtの確認
Googleなどの検索エンジンのクローリング(Webサイトの巡回)を最適化するためのファイルが「robots.txt」です。robots.txtは各Webサイトで持っており、クローリング時にアクセスを許可 または 禁止するURLを定義しています。
「robots.txt」が見つからない場合もありますが、見ることができればスクレイピング先へのアクセスが禁止されていないか確認できます。
詳細は下記サイトの説明を参考にさせてもらいました。
スクレイピング、クローリングする時の注意点 — Pythonオンライン学習サービス PyQ(パイキュー)ドキュメント
みんなの株式のrobots.txtを確認してみます。スクレイピングしたいのは「stock/」以下です。具体的には「stock/銘柄のコード/」になりますが、禁止されていないようです。
User-Agent: * Allow: / Sitemap: https://assets.minkabu.jp/concerns/sitemap/sitemap.xml.gz ...(中略)... Disallow: /user/follow/ ...(中略)... Disallow: /stocks/pick/open_form Disallow: /stock/*/community/edit ...(中略)...
[4] ライブラリをインストールする
pip3コマンドでRequestsとBeautifulSoupをインストールします。
pip3 install requests --user pip3 install bs4 --user
また、取得したデータを加工しグラフ表示するために、pandasやmatplotlibもインストールします。
pip3 install numpy --user pip3 install pandas --user pip3 install matplotlib --user
[5] HTMLの中身を確認する
ピンク枠で囲った部分(単元株数やPER)のHTMLを、ブラウザのデベロッパーツールで確認します。
以下のように、リスト要素(ul, li)を使っており、li要素の中にさらにリスト(dt, dd)を持っています。欲しい情報はdt, dd要素に格納されていることが分かりました。
<div class="ly_col ly_colsize_6_fix"> <ul class=" md_list"> <li class="ly_vamd"> <dt class="ly_vamd_inner ly_colsize_3_fix wsnw">単元株数</dt><dd class="ly_vamd_inner ly_colsize_9_fix fwb tar wsnw">100株</dd> </li> <li class="ly_vamd"> <dt class="ly_vamd_inner ly_colsize_3_fix wsnw">PER<span class="fss">(調整後)</span></dt><dd class="ly_vamd_inner ly_colsize_9_fix fwb tar wsnw">12.39倍</dd> </li> <li class="ly_vamd"> <dt class="ly_vamd_inner ly_colsize_3_fix wsnw">PSR</dt><dd class="ly_vamd_inner ly_colsize_9_fix fwb tar wsnw">0.83倍</dd> </li> <li class="ly_vamd"> <dt class="ly_vamd_inner ly_colsize_3_fix wsnw">PBR</dt><dd class="ly_vamd_inner ly_colsize_9_fix fwb tar wsnw">0.77倍</dd> </li> </ul> </div>
[6] ソースコード
[6-1] HTML取得・解析開始
import requests from bs4 import BeautifulSoup # 指定URLのHTMLデータを取得 url = "https://minkabu.jp/stock/9020" html = requests.get(url) # BeautifulSoupのHTMLパーサーを生成 soup = BeautifulSoup(html.content, "html.parser")
[6-2] リスト要素の解析
ul要素のclass名"md_list"で抽出したいところですが、他の箇所でも使われていました。なので、全li要素を抽出して、li要素内のdd, dt要素を取り出していきます。
# データ格納用のディクショナリを準備 basic_info = {} # 全<li>要素を抽出 li_all = soup.find_all('li') for li in li_all: # <li>要素内の<dt>要素を抽出 dt = li.find('dt') if dt is None: # <dt>要素がなければ処理不要 continue # <li>要素内の<dd>要素を抽出 dd = li.find('dd') # <dt><dd>要素から文字列を取得 key = dt.text value = dd.text # ディクショナリに格納 basic_info[key] = value
[6-3] 取り出した結果
以下の情報が取得できました。
print(basic_info) #{'始値': '6,510.0円', # '高値': '6,580.0円', # '安値': '6,479.0円', # '配当利回り': '2.53%', # '単元株数': '100株', # 'PER(調整後)': '12.39倍', # 'PSR': '0.83倍', # 'PBR': '0.77倍', # '出来高': '1,965,800株', # '時価総額': '2,458,450百万円', # '発行済株数': '377,932千株', # '株主優待': '株主優待割引券、自社施設サービス券、人間ドック割引券', # '購入金額': '最安---'}
意図せず、広い範囲の情報が取れましたが、結果オーライです。
「購入金額」のみ情報を取ってこれていませんが、これはスクリプトによって表示する情報(HTMLの中身)を変えていることが理由です。
終わりに
今回は1銘柄の基本指標を取得するところまで行いました。次回は、複数銘柄の情報を取得し統合します。
*1:Lorenzo CafaroによるPixabayからの画像