気象情報のスクレイピング【入門編】

**【2023年4月15日】**
**気象庁では、2021年2月16日に気象庁ホームページのリニューアルがあり、本記事のスクレイピング方法では気象情報の取得ができないようになりました。**
**つきましては、上記に対応し新しい記事を掲載しましたので下記をご参照ください**

* **[【Colab / Python】気象庁API - 気象データの収集](https://qiita.com/T_Ryota/items/ef96d6575404a0fd46dd)**

---

**本記事は [マイナビ Advent Calendar 2019](https://qiita.com/advent-calendar/2019/mynavi) の11日目の記事になります。**

私は気象好きの社会人1年目です。
今年4月に新卒としてマイナビに入社し、ビッグデータやらAIやらを扱う部署に配属になりました。
記事も初投稿なので温かい目で拝見して頂けれると幸甚です。

## 今回の取り組み
題名の通り、"気象情報をスクレイピングより取得する"ものになります。
今回は入門編なので概論的な話は抜きにして、
どのようなソースでスクレイピングができるのか、実際にやってみましょう。

## スクレイピング

### 注意

概論的な話は抜きにして...と言っていたものの早速無視をしてしまいました。  
下記はスクレイピングを初めてされる方へ注意事項です。
これを注意するだけで皆んなが幸せになるので一読お願いします。

- [岡崎市立中央図書館事件(Librahack事件) - Wikipedia](https://ja.wikipedia.org/wiki/%E5%B2%A1%E5%B4%8E%E5%B8%82%E7%AB%8B%E4%B8%AD%E5%A4%AE%E5%9B%B3%E6%9B%B8%E9%A4%A8%E4%BA%8B%E4%BB%B6)
- [Webスクレイピングの注意事項一覧](https://qiita.com/nezuq/items/c5e827e1827e7cb29011) 

### 今回のスクレイピングの対象となるWebサイト
- [気象庁](http://www.jma.go.jp/jma/index.html)  

### スクレイピングを行う箇所
下記の気象庁のページ内にある天気概況をスクレイピングします。

- [気象庁 | 天気予報：東京都](http://www.jma.go.jp/jp/yoho/319.html)

<img width="600" alt="スクリーンショット 2019-12-10 21.19.50.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214818/5101afae-9be2-861b-90e7-a80dfb8f4777.png">

### 実践
Pythonを用いてスクレイピングを行う際に利用するモジュールはいくつかあるとは思いますが、
ここでは``BeautifulSoup``と``requests``の２つを使用します。

よし、実践！

```python

from bs4 import BeautifulSoup
import requests

url = "http://www.jma.go.jp/jp/yoho/319.html"
req = requests.get(url).text
soup = BeautifulSoup(req, "html.parser")

forecast_text = soup.find('pre', class_="textframe").text

print(forecast_text)
```
以下は出力結果！

```
天気概況
令和元年１２月１０日１６時４３分　気象庁予報部発表

　伊豆諸島南部、小笠原諸島では、高波に注意してください。伊豆諸島では
、竜巻などの激しい突風や急な強い雨、落雷に注意してください。

　高気圧が日本のはるか東と西日本にあって、それぞれ東へ移動しています。引き続き、房総半島沖から伊豆諸島にかけては気圧の谷となっています。

　東京地方は、曇りとなっています。

　１０日は、気圧の谷や湿った空気の影響により、曇りとなるでしょう。伊豆諸島では、雨や雷雨となる所がある見込みです。

　１１日は、気圧の谷や湿った空気の影響により曇りとなりますが、朝から昼過ぎは高気圧に覆われて晴れるでしょう。伊豆諸島では、雨や雷雨となる所がある見込みです。

【関東甲信地方】
　関東甲信地方は、曇りや晴れとなっています。

　１０日は、気圧の谷や湿った空気の影響により、関東地方は曇りで沿岸部では雨、伊豆諸島では雷雨の所があるでしょう。甲信地方や群馬県では高気圧に覆われて晴れる所もある見込みです。

　１１日は、気圧の谷や湿った空気の影響により、朝晩を中心に曇りで沿岸部では雨、伊豆諸島では雷雨の所があるでしょう。日中は高気圧に覆われて晴れる所もある見込みです。

　関東地方と伊豆諸島の海上では、１０日から１１日にかけて、うねりを伴って波が高いでしょう。船舶は高波に注意してください。
```
おお！
ちゃんとスクレイピングが出来たようです。
数行のソースでサイト内の文章を取得することができました！
ライブラリの読み込みと出力部分を抜くと４行程になりますね！
簡単！

### ソースについて
ソースについて全く説明がないのも如何なものかと思うので、
ざっくりソースの動作を説明しようと思います。

#### スクレイピング対象になるWebサイトのURLを指定
```python

url = "http://www.jma.go.jp/jp/yoho/319.html"
```

#### Webページから内容を取得
``requests.get()``でスクレイピング対象のWebページから内容を取得します。

```python

req = requests.get(url).text
```

#### htmlパース用のオブジェクト作成
ここではhtmlで書式化されているテキストファイルを
``BeautifulSoup``により解釈しています。
これにより後のWebページ内の要素の探索が容易になります。

```python

soup = BeautifulSoup(req, "html.parser")
```

#### 指定したタグ内のテキストを取得
``find()``は条件に合致する1番最初に見つかった要素を返しています。
ここで言うと抽出する箇所は、
``<pre class="textframe">天気概況～～</pre>``のように
タグが``pre``要素、``class``が``textframe``にあたるので、それに対応して
``.find('pre', class_="textframe")``のような記述になっています。

そして、``.text``で指定した要素内のテキストを抽出する形になります。
今回は探索した際に
Webページ内で該当する要素が一つだけだったため``find()``を使用していますが、
該当する要素が複数ある場合は``find_all()``を使用する必要があります。
[BeautifulSoup | find()/find_all()](https://www.crummy.com/software/BeautifulSoup/bs4/doc/#find)

```python

forecast_text = soup.find('pre', class_="textframe").text
```


## 終わりに
今回は気象情報のスクレイピングを紹介させて頂きました。
上記の様に数行のソースで簡単にスクレイピングが行えるので皆さんも是非やってみて下さい!

## おまけ

スクレイピングだけだともの寂しかったので
おまけで先程の出力結果に対して正規表現で、
欲しい文章を抽出しようと思います。

抽出するのは下記の赤線箇所
<img width="600" alt="東京地方 | 天気概況" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214818/d7cdb8fc-16ba-31ba-b381-481b7c0fac06.png">

以下はソースの内容

```python

import re

start_text = "東京地方"
end_text = "。"

compile_text = re.compile(r'{start}.*?{end}'.format(start=start_text, end=end_text), flags=re.DOTALL)
extraction_sentece = compile_text.search(forecast_text)
result = extraction_sentece.group()

print(result)
```
以下は出力結果

```
'東京地方は、曇りとなっています。'
```

😊