pythonでwebスクレイピング

ハッカソンの開発の一端でpythonでwebスクレイピングを行い、

取得した情報をテンプレートに表示するということを行いました。

 

まず開発環境情報です。

・pipenvでパッケージ管理

・Python 3.6.5

・Django 2.1.3

 

 

スクレイピングを行うにあたって、まずネット上のリソース取得のためと、スクレイピングを行うためにライブラリ(パッケージ)が必要になります。

  • requests : HTTP通信のライブラリ
  • beautifulsoup4 : html解析のライブラリ
  • lxml : html解析(beautifulsoup4内で使うことになります)

 

ではまず次のように追加していきましょう!

import urllib.request
from bs4 import BeautifulSoup

このスクレイピングのためのBeautifulSoupですが、これを利用するためには

pipを使ってパッケージをインストールしなければならないのでインストールします。

また後程出てくるlxmlもパッケージが必要になりますので一緒にインストールします。

 

 

pipenvを使った仮想環境で開発しているので

Pipfileがおいてあるディレクトリに移動して、仮想環境のシェルに入るために

$pipenv shell

を行ったあとに

pipenv install beautifulsoup4

を行います。

 

pipenvを使ってない方は

$pip install beautifulsoup4

で大丈夫ですね。

もしインストールに失敗したらpythonのバージョンとパッケージのバージョンが対応してないという可能性があります。python3だとpipの代わりにpip3 とすればインストール出来たりもありますので試してみてください。

 

それからlxmlもインストールしておきます。

$pipenv install lxml

 

 

今回のハッカソンでの開発テーマが「防災」で

スクレイピングで緊急地震速報がほしかったので 気象庁からその情報をとってきます。

偶然で驚いたのですが、気象庁からデータを取ってくるというのをすでにやられている方が

いたので参考にさせて頂きました。(https://algorithm.joho.info/programming/python/beautifulsoup4-quake-sindo/)

 

 

コードが以下になります。

resource = urllib.request.urlopen("http://www.jma.go.jp/jp/quake/quake_sindo_index.html") #気象庁のURL
soup = BeautifulSoup(resource, "lxml") # html解析
info = soup.find_all("div", attrs={"id": "info", "class": "infotable"})
text = info[0].text

 

 

resourceでwebページの情報を取得して、BeautifulSoupでhtml情報を取得しています。

ここからページの情報を取りたい部分を抽出するのにfind()やfind_all()メソッドを利用します。

 

取得の方法はいろいろありますが、ここでは、3行目のとおりfind_allメソッドで

「div」タグの「idはinfo」で「class名がinfotable」の部分をとってきています。

取得した情報をprintで出力して見てみますと特殊な型になっているのが確認できますね。

print(type(info))
→ <class 'bs4.element.ResultSet'> # 結果

 

中身はどうなっているかというと

print(info[0])
<div class="infotable" id="info">
<table>
<caption>震度速報</caption>
<tr>
<th>地震の揺れの検知日時</th>
<th>最大震度</th>
<th>情報発表日時</th>
</tr>
<tr><td nowrap=""><a href="./20181107223709453-08073528.html">2018年11月 8日07時35分</a></td><td nowrap="">震度3</td><td nowrap="">11月 8日07時37分</td></tr>
<tr><td nowrap=""><a href="./20181105145007453-05234705.html">2018年11月 5日23時47分</a></td><td nowrap="">震度3</td><td nowrap="">11月 5日23時50分</td></tr>
<tr><td nowrap=""><a href="./20181104232059453-05081924.html">2018年11月 5日08時19分</a></td><td nowrap="">震度3</td><td nowrap="">11月 5日08時20分</td></tr>
<tr><td nowrap=""><a href="./20181104192753453-05042617.html">2018年11月 5日04時26分</a></td><td nowrap="">震度4</td><td nowrap="">11月 5日04時27分</td></tr>
<tr><td nowrap=""><a href="./20181102075635453-02165401.html">2018年11月 2日16時54分</a></td><td nowrap="">震度4</td><td nowrap="">11月 2日16時56分</td></tr>
<tr><td nowrap=""><a href="./20181102075537453-02165401.html">2018年11月 2日16時54分</a></td><td nowrap="">震度4</td><td nowrap="">11月 2日16時55分</td></tr>
</table>
</div>

タグがきちんと取得できているのが分かります。

 

特殊な型のオブジェクトですがlistのように使えて、情報が0番目に入っているので、

info[0]とし、.textとすることでhtmlタグを除いて中身のテキスト部分が取得できます。

しかし直接[0]要素を指定するのではなく、よく見かけるのはfor文で取得する方法なのでfor文で取得する場合も載せておきます。

text = [x.text for x in info]

 

では試しにprint(text)で出力してみますと、タグを除いた中身だけきちんと取得できていることが確認できました。

震度速報

地震の揺れの検知日時
最大震度
情報発表日時

2018年11月 8日07時35分震度311月 8日07時37分
2018年11月 5日23時47分震度311月 5日23時50分
2018年11月 5日08時19分震度311月 5日08時20分
2018年11月 5日04時26分震度411月 5日04時27分
2018年11月 2日16時54分震度411月 2日16時56分
2018年11月 2日16時54分震度411月 2日16時55分

 

 

ここで一つ少し厄介なのが、変数textにこれだけの文字列が全て入ってることですね。

文字列操作を駆使して扱いやすい形にカスタマイズしましょう!

 

 

話を戻しまして、気象庁のこの緊急速報を取ってくることには上のように成功したのですが、

どこで起こった地震なのか、などの詳細情報がありません。そこで気象庁のページをみると、

検知時間のところがリンクになっててこれに飛ぶと

 

詳細情報が載っていました!

 

さっきのよりもほしい情報はこちらなので、こちらの情報も取得していきます。

 

そのためには

・詳細ページのリンクの情報が必要となるので

link_detail = info[0].a.get("href")

で取得します。

 

info[0]に入っているタグを取得するのは「ドット+タグ名」です。

それからタグ内の属性を取得するのに.get(“属性名”)とします。

ちなみに複数aタグがあってもこれで得られるのは最初のaタグになります。

これで得たURLを確認してみますと、

print(link_detail)
→ ./20181107223709453-08073528.html

相対パスなのでこのままでは使えませんね。

 

ですので、あらかじめ気象庁のこのページより上の階層のリンクの部分を用意しておき、

余分なドットを消してつなげることで正しいリンクが得られますね。

# 詳細URL取得
base_link = "http://www.jma.go.jp/jp/quake"
link_detail = infotable[0].a.get("href")
link = base_link + link_detail.lstrip(".") #lstrip(".")で左端のドットを消している

 

 

リンクが得られたので、また最初と同様に

resource_detail = urllib.request.urlopen(link) 
soup_detail = BeautifulSoup(resource_detail, "lxml") # html解析

としていくことで情報が取得できました。

 

 

こんな感じであとはフロントで綺麗にしてやると以下のようにできました。

 

 

以下は参考サイトと自分が見返したいサイトです。

 

pipenvの参考↓

 

BeautifulSoupのタグの取得方法の参考↓

【Qiita】PythonとBeautiful Soupでスクレイピング

 

BeautifulSoupで取得した内容の処理の参考↓

【Qiita】webスクレイピングで今日の天気と気温を取得

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です