hkのweblog

ひよっこエンジニアがにわとりになるまでの軌跡

BeautifulSoupで東証一部上場企業の株価をスクレイピングしてみた

東証一部上場企業の従業員数、売上高等のデータを収集し、これらの指標と株価にはどの程度の相関があるのか調べるために単回帰してみる、ということをやってみようと思っています。
この記事ではその工程の一部である「東証一部上場企業のデータをスクレイピングで集める」部分を書いてみます。
私は統計の専門家ではないし、日常業務ではPythonを全く使っていません。変なところがあったらすいません。

環境

  • macOS High Sierra 10.13.2
  • Python 3.5(Anacondaでインストール)
  • pyenv+virtualenv使用
  • BeautifuSoup(4.6.0) こんなもんです。

大雑把な手順

  1. 証券コードが格納されているcsvファイルを用意する
  2. csvから証券コードを取得する
  3. htmlを取得する
  4. 必要なデータを取り出す
  5. 使用しやすいようにデータを加工する

証券コードが格納されているcsvファイルを用意する

これは技術でも何でもないのですが、
私は日本取引所グループのページから拝借しました。
Excelの機能で業種や取扱市場を絞り込んで必要な証券コードを抽出、csvに貼り付けます。
何だかんだ言ってもExcelって便利ですね。

csvから証券コードを取得する

先ほど取得したcsvをcode.csvとし、同じディレクトリ内でcollect_data.pyを作成します。

# -*- coding: utf-8 -*-

import csv

# 証券コードを読み込む
with open('code.csv', 'r', encoding='sjis') as f:
    reader = csv.reader(f)
    code_list = [row[0] for row in reader]

こんな感じでcode_listというリストに証券コードを格納することができます。
with openで書いていくとcloseし忘れる…といったことがないので便利ですね。
Excelで作成したcsvファイルは文字コードがShift-JISになるみたいなので、encoding='sjis'を指定しています。

htmlを取得する

さて、スクレイピングを始めていきます。
今回は日経新聞のサイトからデータを拝借しました。(規約的にNGだったらごめんなさい…)

import urllib.request

for code in code_list:
    url = "https://www.nikkei.com/nkd/company/gaiyo/?scode=" + code
    html = urllib.request.urlopen(url)
    soup = BeautifulSoup(html, "html.parser")

先ほど取得したcode_listから各証券コードを取り出し、URLを作ります。
このURLからhtmlを取得、HTMLパーサーで読みます。

必要なデータを取り出す

import re
from bs4 import BeautifulSoup 
comma_pattern = r'([0-9,--]+)'

# ここからは先程のfor文の中に書いています
    stock_price = re.findall(comma_pattern, soup.find("dd", class_="now").text)[0] #株価
    employee = re.findall(comma_pattern, soup.find("td", text=re.compile("\s人")).text)[0] #従業員数

soup.find('HTMLタグ名', 条件)という形で条件に当てはまる最初のHTMLを取得できます。
findの部分をfind_allにすると条件に当てはまる全てのHTMLをリストの形で取得できます。
classやidで一つに絞れると非常にやりやすいのですが、必ずしもそうはなっていなかったりします。まあスクレイピングしやすいようにサイトを作る人なんていないですよね…
そんな時は上記の従業員数の例のように絞ることもできます。
さらに正規表現を使ってデータを取っています。
ちなみにcomma_patternにハイフンやら記号が含まれているのは、持株会社等で従業員数が書かれていない会社が散見されたからです。
他にも様々な抽出手段があるようですが、詳しくはBeautifulSoupのドキュメントをご参照ください。

使用しやすいようにデータを加工する

ここまででも必要なデータは揃いますが、この後回帰分析を行うことを考えて、数値データからカンマを取り除いておきます。

# ここからは先程のfor文の中に書いています
    stock_price = re.findall(comma_pattern, soup.find("dd", class_="now").text)[0].replace(",","") #株価
    employee = re.findall(comma_pattern, soup.find("td", text=re.compile("\s人")).text)[0].replace(",","") #従業員数

所感

いざやってみるとデータを集めづらいサイトが多いです…
BeautifulSoupだけで完結せずに正規表現も使わざるを得ない場合も多そうです。
とはいえ、これだけのコード量でデータを収集できてしまうのは素晴らしいなと思います。
気が向いたら回帰分析についても書いてみようと思います。