#0.はじめに
pythonを投資活用に使う目的で調べたまとめ記事の第2弾の続き記事です。
今回は実際にスクレイピングを試してみます
*前回記事
PythonでWebスクレイピング①(スクレイピング事前知識)
#1.前回のおさらい&スクレイピング対象の確認
前回の記事で唯一「robots.txt: Allow:/ 」だった株式投資メモを対象に色々試していく。
#まずはreppyで確認(前回のおさらい)
from reppy.robots import Robots
robots = Robots.fetch('https://kabuoji3.com/robots.txt')
print(robots.allowed('https://kabuoji3.com/', '*'))
False
↑でFalseとなってしまうが、これは(reppyで取得するために)株式投資メモのrobots.txtの書き方に問題がある為である。
通常Allow:の後にスペースが入るのが普通なのだが、このサイトにはついていない。
よって前回記事で紹介したreppyではうまく取得できなかった模様。NGの場合は自分でrobots.txtを確認しにいくことが大事ですね。
なお、今回は例として下図の赤枠部分を取得したいケースをとりあげる。(URL:https://kabuoji3.com/stock/)
#2.該当URLのHTMLを検証して、取得したい部分を探しておく
ここで一旦pythonから離れる。今回の目標は「上場全銘柄の最新株価情報を取得すること」なのだが、何も考えずにURL情報を取得しても同じページ内に存在する不要な情報も取得してしまう(例えばhelpページへのリンクやタイトル情報等)ので、「必要な部分」がHTMLのどこに記述してあるか?を理解しておく必要がある。
するとHTMLの知識が必要・・また言語の勉強・・?となるわけだが、最低限だけ知っておけば問題ない。
しかもGoogle Chromeの場合は「検証」という機能があるので、それも不要である程度対応できる。
対象のURLで左クリックすると、↓のようなコマンドがでてくるはずである。
対象ページ「https://kabuoji3.com/stock/」 の上で検証を表示させてみる
右に検証Windowが出てくる。
検証WindowではHTMLの記述が書かれているが、試しにマウスカーソルを<header id="header" class="">
の部分に
合わせてみると、上図のようにURLの上の方が青くハイライトされていることがわかる。
これはつまり、URLの上の方(タイトルとか)がこの部分に書かれていることを指す。
今回は株価データの表部分が取得したい部分なので、それを検証で出てきたHTMLの中から探していけばいい。
探していくと、`table class="stock_table"`という部分がそうっぽいことがわかる。 で、その中に`thead`と`tbody`というのがあって、それぞれがこの表の「ヘッダー」と「各行の株価データ」であることがさらに検証で表示させていくとわかる。 ちなみに、表要素をHTMLでは`table`と呼ぶので、それで探してもいいかもしれない#3.上場全銘柄の最新株価情報をrequestsコマンドで取得
ここからは2で調べた情報も踏まえてpythonで取得していく。
前回も少し触れたが、BeautifulSoupをインストールしておくこと(pip install beautifulsoup4
)。
事前に確認くんで自分のユーザーエージェント(UA)情報を確認するのが必要になる。
「現在のブラウザー」に記載してある部分がUA情報なので、下記コードを自分の環境に応じて書き直すこと。
※「現在のブラウザー」に出てくる「表示サイズ:~~」という記述は不要なのでコピペしないこと
import requests
from bs4 import BeautifulSoup
import pandas as pd
#スクレイピング対象のURLを入力
url = 'https://kabuoji3.com/stock/'
#確認くんで調べた自分のユーザーエージェント(現在のブラウザー)をコピペ ※環境に応じて書き直す
headers = {"User-Agent": "Mozilla/*** Chrome/*** Safari/***"}
#Requests ライブラリを使用してWebサイトから情報(HTML)を取得する。
response = requests.get(url, headers = headers)
print(response)
<Response [200]>
すると3桁のHTTPステータスコード
が返ってくる。200(リクエスト成功)が返ってくればOK。
もし403(認証拒否)や404(Not Found※URL不正)が返ってきたら失敗しているので、もう一度記述を見直す。
#4.requestsコマンドで取得した中身を解析し、必要な部分を取り出す
次にBeautiifulSoupで取得したHTMLの中身を解析して、必要部分をタグ指定して取り出す
#取得したHTMLからBeautifulSoupオブジェクト作成
soup = BeautifulSoup(response.content, "html.parser")
"""
まずは株価表のヘッダー部分を取得する。
2でHTMLの中でヘッダー部分に「tr」というタグが付いているのはわかっているので、それを探す。
やり方はいくつかあるが、要は<thead>タグの中にある<tr>を全部抜き出せばヘッダー全部が取得できる。
"""
#まずはtheadをfindメソッドでコマンドで検索し、その中のtrをfind_allメソッドですべて抽出
tag_thead_tr = soup.find('thead').find_all('tr')
print(tag_thead_tr)
[<tr>
<th>コード・名称</th>
<th>市場</th>
<th>始値</th>
<th>高値</th>
<th>安値</th>
<th>終値</th>
</tr>]
#同様に株価部分を取得していく。tbodyタグの内にあるtrタグでひとまとまりになっているのはすでにわかっている
tag_tbody_tr = soup.find('tbody').find_all('tr')
#数が多いので、0番目だけ表示
print(tag_tbody_tr[0])
<tr data-href="https://kabuoji3.com/stock/1305/">
<td><a href="https://kabuoji3.com/stock/1305/">1305 ダイワ 上場投信-トピックス</a></td>
<td>東証ETF</td>
<td>1883</td>
<td>1888</td>
<td>1878</td>
<td>1884</td>
</tr>
これでうまく取得できていることがわかる。
#5.取得した情報をpandasで表示させる
pythonで表を扱いやすいpandasでまとめてみる。
import pandas as pd
#取得したヘッダー部をさらにthで検索してテキスト化する ※[0]としているのは、find_allを重ねることが出来ないため。
head = [h.text for h in tag_thead_th[0].find_all('th')]
#株価部分を当てはめていく
data = []
for i in range(len(tag_tbody_tr)):
#各カラムのデータはtdタグに格納されているので取り出す
data.append([d.text for d in tag_tbody_tr[i].find_all('td')])
df = pd.DataFrame(data, columns = head)
#データフレーム最初2行だけ表示
df.head(2)
表示結果
コード・名称 | 市場 | 始値 | 高値 | 安値 | 終値 | |
---|---|---|---|---|---|---|
0 | 1305 ダイワ 上場投信-トピックス | 東証ETF | 1883 | 1888 | 1878 | 1884 |
1 | 1306 (NEXT FUNDS)TOPIX連動型上場投信 | 東証ETF | 1861 | 1867 | 1856 | 1863 |
これでpythonで扱いやすい形に変形ができた。あとは煮るなり焼くなり好きに加工して使えばいいし、
pandasのto_csv
メソッドでcsvに保存もできたりする。
#6.最後に
記事自体は長くなっているが、コード自体も短く取得できていることがわかる。
要するに、HTMLのどこのタグに取得したい情報があるか?を探すだけでいいのである。
もちろんこれで取得できないケースも多く存在する(javascript等絡んでいる場合)が、それはその時に応じて身に着ければいいと思う。
次回は第3回として、1回目と2回目を組み合わせてデータベースにスクレイピングで取得した株価を格納する記事を予定です
#7.(おまけ)簡単なHTMLの補足
一応 https://kabuoji3.com/stock/ のHTMLを簡単に解説する。
検証でHTMLを表示させて、body・・の部分を折りたたむと下図のようになる。
つまり簡単にすると⇓のようになっている。
<!-- 最初にHTML宣言を行う。lang="ja"で日本語を扱うよ~という意味-->
<html class=・・>
<!-- ここはブラウザには表示されないhead部分。文字コードやページ検索時に検索結果として表示される部分などが記述-->
<head>...</head>
<!-- ここがHTML本体のbody部分。divタグでページ全体をグループ分けしつつ作られる-->
<body class=・・・>...</body>
<!-- HTML記述終了-->
</html>
ページ内HTMLのざっくりとしたbodyの構成を下に書いておく。
階層に分けてインデントを入れている。実際にページを見たり検証をクリックしながら確認するとわかりやすい。数が多くぐちゃぐちゃしてるように見えるが、確認したい箇所のdiv id
にはダブりがないので着目していくだけである。
<!-- ▼bodyの部分だけ抜粋-->
<body>
<div id="wrapper">
<!-- ▼ヘッダー(見出し)部分-->
<header id="header">...</header>
<!-- ▼グローバルナビ(MENUを押すと出てくる)部分-->
<div id="gNav_wrap">...</div>
<!-- ▼ページメイン部分-->
<div id="contents_wrap">
<!-- ▼メイン部分-->
<div id="container_in">
<!-- ▼メイン部分-->
<div id="main">
<!-- ▼ここからの下層重要な箇所だけ。それ以外は省略-->
<div class="data_contents">
<!-- ▼株価のテーブル(表)-->
<table class="stock_table">
<!-- ▼表のヘッダー(カラム)-->
<thead>
<!-- ▼カラム-->
<tr>...</tr>
</thead>
<!-- ▼表の中身データ部分-->
<tbody>
<!-- ▼各行毎に株価データ-->
<tr>...</tr>
</tbody>
</table>
</div>
</div>
<!-- ▼Data Menu部分-->
<div id="side">...</div>
</div>
<!-- ▼HOME,PAGETOPのリンクがあるナビ部分-->
<div id="gNav_wrap">...</div>
<!-- ▼フッター(一番下に配置される情報がまとまった)部分-->
<div id="gNav_wrap">...</div>
</div>
<!-- ▼スクリプト部分。javascriptや外部スクリプトを読み込んだりする場合に使用する-->
<script>...</script>
</body>