気象データを Python でスクレイピングする方法（10分値データ）

# きっかけ

気象データを取得したいと思い気象庁のサイトにアクセスしたところ、なぜかエラーになりCSVダウンロードができませんでした。

Web上での表示は問題無くできますので、この表データをCSV化できないかを考えました。

https://www.data.jma.go.jp/gmd/risk/obsdl/index.php

# すでにやられていたこと

調べてみると、気象データのスクレイピングは様々な方がチャレンジされていました。
なかでも、こちらの記事のソースコードをそのまま実行すれば私の環境でも動きました。
非常に助かりました。

https://www.gis-py.com/entry/scraping-weather-data

ちなみに、Pythonでは、BeautifulSoupというライブラリを使うのが定石のようです。
このようなコマンドでインストールできます。

```pip3 install beautifulsoup4```


# 今回試したこと

前述のブログでは1時間値を取得していましたので、10分値のデータを取得できるようにコードを変更してみました。
`prec_no`が都道府県の番号、`block_no`が地点の番号を示しているので、実行する時には好きな番号に書き換えてもらえばと思います。

https://www.data.jma.go.jp/obd/stats/etrn/view/10min_s1.php?prec_no=44&block_no=47662&year=2023&month=01&day=01&view=p1

```python:tenki.py
# -*- coding: utf-8 -*-
import os
import datetime
import csv
import urllib.request
from bs4 import BeautifulSoup

def str2float(weather_data):
    return weather_data

def scraping(url, date):

    # 気象データのページを取得
    html = urllib.request.urlopen(url).read()
    soup = BeautifulSoup(html)
    trs = soup.find("table", { "class" : "data2_s" })

    data_list = []
    data_list_per_hour = []

    # table の中身を取得
    for tr in trs.findAll('tr')[3:]: # 変更
        tds = tr.findAll('td')

        if tds[1].string == None:
            break;

        data_list.append(date)
        data_list.append(tds[0].string)
        data_list.append(str2float(tds[1].string))
        data_list.append(str2float(tds[2].string))
        data_list.append(str2float(tds[3].string))
        data_list.append(str2float(tds[4].string))
        data_list.append(str2float(tds[5].string))
        data_list.append(str2float(tds[6].string))
        data_list.append(str2float(tds[7].string))
        data_list.append(str2float(tds[8].string))
        #data_list.append(str2float(tds[9].string)) # 変更
        #data_list.append(str2float(tds[10].string))
        #data_list.append(str2float(tds[11].string))
        #data_list.append(str2float(tds[12].string))
        #data_list.append(str2float(tds[13].string))

        data_list_per_hour.append(data_list)

        data_list = []

    return data_list_per_hour

def create_csv():
    # CSV 出力先ディレクトリ
    output_dir = r"/Users/username/Downloads"

    # 出力ファイル名
    output_file = "weather.csv"

    # データ取得開始・終了日
    start_date = datetime.date(2023, 1, 1)
    end_date   = datetime.date(2023, 1, 2)

    # CSV の列
    fields = ["年月日", "時間", "降水量", "気温", "相対湿度",
              "平均風速", "平均風向", "最大瞬間風速", "最大瞬間風向", "日照時間"]

    with open(os.path.join(output_dir, output_file), 'w') as f:
        writer = csv.writer(f, lineterminator='\n')
        writer.writerow(fields)

        date = start_date
        while date != end_date + datetime.timedelta(1):

            # 対象url（10分値の場合）
            url = "http://www.data.jma.go.jp/obd/stats/etrn/view/10min_a1.php?" \
                  "prec_no=46&block_no=0388&year=%d&month=%d&day=%d&view="%(date.year, date.month, date.day)
            data_per_day = scraping(url, date)

            for dpd in data_per_day:
                writer.writerow(dpd)

            date += datetime.timedelta(1)

if __name__ == '__main__':
    create_csv()
```

# 補足
10分値のデータは1時間とは取得できる表の列名が異なるため、その部分だけ書き換えています。
元の記事には、str2float()という関数があったのですが、テキスト値も一律に0に変換されてしまうので、取り急ぎ無意味な処理にしています。
もっと簡単にしたり、数値と文字列で適切な処理に変更することもできそうです。