あっぱれ日和、 - What a "Appare" day -

あっぱれ日和、 - What a "Appare" day -

通りすがりのしがない映画好きが綴る、モノづくりの記録や備忘録。そして、影響を受けた映画の記録。

スクレイピング メモ

はじめに、

この記事はWebスクレイピングに関する備忘録として記録します。
自分が実際にスクレイピングを実装した際に今後使えるなと思ったら、適宜更新していく予定ですのでよろしくお願いします。
言語はpythonです。
メモのような感じで書いていきます。

サイトの動的な値をとってくる

(20200809~記)
今回は株価のサイトの値をとってくる
今回は株探のサイトの日産(7201)で試してみます。

決算のページは以下のような感じ

f:id:appare99:20200809161143p:plain
2020年8月9日現在の日産の決算ページ(株探)

ここの2020年3月の営業利益の部分(以下の赤い矢印が指している赤い枠の部分)の値をとってくる
f:id:appare99:20200809164312p:plain
ここの値は「検証」で観てみるとtr要素(Table Row)の中の「セル」をtd要素(Table Data)に値が入っているのが分かります。
f:id:appare99:20200809164322p:plain

よってポイントは以下の通り

  • タブの値をとってくる
  • とってきた値の数字のみを抽出(ただしマイナスの文字は残す)

出たエラーも含めて手順を踏まえて書いていく

  • (1) まずhtmlの情報を収集するためにBeautifulSoupを使用する
  • (2) 対象のtdの値を抽出する。今回はwebページ(html)の中の46番目のtdの値なので[46]と指定する。
  • (3) 正規表現を使用して数字のみを抽出する。詳細は以下のメモに記載。
import re
import urllib.request, urllib.error
from bs4 import BeautifulSoup

html = urllib.request.urlopen("https://kabutan.jp/stock/finance?code=7201") # (1)まずhtmlの情報を収集するためにBeautifulSoupを使用する

soup = BeautifulSoup(html)
td = str(soup.find_all("td")) [46] #(2) 対象のtdの値を抽出する。今回はwebページ(html)の中の46番目のtdの値なので[46]と指定する。

value = re.sub(r"[^-\d]", "", td) #(3) 正規表現を使用して数字のみを抽出する。詳細は以下のメモに記載。

print(int(value))
# printの出力は-40469となる
上記コード化する際の注意点 and メモ
  • (2)のところでは-40,469という値が入ってくる。この時td = str(soup.find_all("td") [46])ではなく、td = soup.find_all("td") [46]とすると(3)のところで「expected string or bytes-like object」というエラーが出るので注意。
  • (2)の段階でtdに入っている値は-40,469なのでこれを-40469という値にしたい。このため数字とマイナス(-)の文字のみ抽出する必要がある((3)の処理)。これには正規表現を用いる。[^-\d]ではマイナス(-)と数字(\d)以外([^])の文字は""でなしにするという意味。
別解(こっちの方が汎用性があるのでいいかも)

例えば、上記画像の日産の決算の過去最高の売上高の表から過去最高の売上高の値、12189519を取り出したいと思った時、上記の方法で考えると

td = str(soup.find_all("td") [237])

とすれば取り出せる。
一方で以下の画像のセレス(3969)の決算の過去最高の売上高の表から過去最高の売上高の値、16510を取り出したいと思った時td = str(soup.find_all("td") [237])では1.34という値が抽出されてしまう。
tdのナンバリングが銘柄ごとの決算の数などによってかわってきてしまう。

f:id:appare99:20200810111550p:plain

これに対しての解決策としてテーブルをまず取り出してそのテーブルの中のtdのナンバリングで値を抽出するという方法で他の銘柄に対しても値をとってこれる。
今回の場合、過去最高の売上高の表はこのhtmlの13番目になるので上記のコードの「td = str(soup.find_all("td") [237])」の部分を以下に変えればよい。

table = soup.find_all("table")[12]
value = table.find_all("td")[0]

詳しく見ると、table = soup.find_all("table")[12]の段階で以下のような値がとってこれる。

<table>
<thead>
<tr>
<th class="fb_01" scope="col"> </th>
<th class="fb_02" scope="col">売上高</th>
<th class="fb_02" scope="col">営業益</th>
<th class="fb_02" scope="col">経常益</th>
<th class="fb_02" scope="col">最終益</th>
<th class="fb_03" scope="col">修正1株益</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">過去最高</th>
<td>16,510</td>
<td>1,221</td>
<td>960</td>
<td>650</td>
<td>62.6</td>
</tr>
<tr>
<th scope="row">決算期</th>
<td>2019.12  </td>
<td>2018.12  </td>
<td>2017.12  </td>
<td>2017.12  </td>
<td>2017.12  </td>
</tr>
</tbody>
</table>

tdの1番目(ナンバリングは0)のところに過去最高値が入っているので「table.find_all("td")[0]」でとってきたtableの値からとりだす。