6
10

More than 3 years have passed since last update.

PythonでWebスクレイピング②(実際に株サイトをスクレイピングする)

Last updated at Posted at 2020-12-20

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を確認しにいくことが大事ですね。

追加されたkernel今のHPのRobots.txt

追加されたkernel本来こうあるべきRobots.txt

なお、今回は例として下図の赤枠部分を取得したいケースをとりあげる。(URL:https://kabuoji3.com/stock/)

2.該当URLのHTMLを検証して、取得したい部分を探しておく

ここで一旦pythonから離れる。今回の目標は「上場全銘柄の最新株価情報を取得すること」なのだが、何も考えずにURL情報を取得しても同じページ内に存在する不要な情報も取得してしまう(例えばhelpページへのリンクやタイトル情報等)ので、「必要な部分」がHTMLのどこに記述してあるか?を理解しておく必要がある。

するとHTMLの知識が必要・・また言語の勉強・・?となるわけだが、最低限だけ知っておけば問題ない。
しかもGoogle Chromeの場合は「検証」という機能があるので、それも不要である程度対応できる。
対象のURLで左クリックすると、↓のようなコマンドがでてくるはずである。


ページのソースを表示:HTMLをそのまま表示する
検証:ページの記述がHTMLのどこを指すのか?がすぐにわかる(それだけではないが、この記事ではメイン)

対象ページ「https://kabuoji3.com/stock/」 の上で検証を表示させてみる

対象ページの検証

右に検証Windowが出てくる。
検証WindowではHTMLの記述が書かれているが、試しにマウスカーソルを<header id="header" class="">の部分に
合わせてみると、上図のようにURLの上の方が青くハイライトされていることがわかる。
これはつまり、URLの上の方(タイトルとか)がこの部分に書かれていることを指す。

今回は株価データの表部分が取得したい部分なので、それを検証で出てきたHTMLの中から探していけばいい。

対象ページの検証
探していくと、table class="stock_table"という部分がそうっぽいことがわかる。
で、その中にtheadtbodyというのがあって、それぞれがこの表の「ヘッダー」と「各行の株価データ」であることがさらに検証で表示させていくとわかる。
ちなみに、表要素を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不正)が返ってきたら失敗しているので、もう一度記述を見直す。

参考:HTTPステータスコードWiki

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>
6
10
0

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
  3. You can use dark theme
What you can do with signing up
6
10