Google ColaboratoryでAMeDASの10分値を取得する

※スクレイピングする際には各所の利用規約に従うようにしてください。
※本記事を参考に実行して生じた不利益等は責任を負えませんのでご容赦ください。

#概要
Google Colaboratoryを利用したWebスクレイピングでAMeDASの10分値を半自動的にダウンロードします。

#はじめに
気象データとして気象庁が公開しているAMeDASの10分値を使用したい場合、
ダウンロードオプションが用意されていないため、何らかの方法で自ら取得する必要があります。

既にPythonを用いたスクレイピングでAMeDASの10分値等をダウンロードする方法が多く公開されていますが、
何より面倒なのは「環境構築」です（筆者の個人的意見です）。
ライブラリのインストールやパスの設定など、できれば省きたいものです。

例えばGoogle Colaboratoryを使用すれば、webブラウザ上で直ぐにPython環境が利用できます。
但し、Google colaboratoryではwebブラウザ上でPython等を記述・実行する環境構築のために、
Jupyterを用いており、この関係でコマンドの記述方法等を多少変更する必要があります。
※厳密にはJupyterのバックエンドであるIpythonの仕様に合わせるため。

そこでこの記事では、Google Colaboratoryに対応したPythonスクレイピングでAMeDASの10分値を取得する方法を紹介します。

#必要なもの
・Googleアカウント

#Google Colaboratoryの準備
Google ColaboratoryはWeb上で簡単にPythonを使用できる無料ツールです。
Google Colaboratoryを利用する環境の用意については、<a href="https://qiita.com/kogetaenoki/private/1bcd0d5535edb6f0d895">別記事</a>に詳細を記載していますので、
ここでは簡単に説明します。

ブラウザからGoogle Driveを開き、左上の`新規`から`その他`、`アプリの追加`へと進みます。
アプリ一覧の中に`Colaboratory`があるので、これをインストールします。

インストール後はGoogle Driveの`新規`から`その他`へと進むことで、
`Colaboratory`を利用できるようになります。

##Google Colaboratoryの使い方（今回必要な分だけ）
上記手順で進めるとGoogle Colaboratoryの編集画面が立ち上がります。

（説明が下手ですが）黒丸に灰色の三角形内包されているものが実行ボタンです。
その右側の灰色の部分がコードを入力できるエリアです。ここに諸々を書き込みます。

プログラムの実行には先の実行のボタンを押しても良し。
`Ctrl+Enter`でも良し。

標準出力/エラー出力先はコード入力エリアの下方にあります。

また、画面左側の4つのアイコンが順に[目次][検索と置換][コードスニペット][ファイル]ですので、
ディレクトリ構造等を確認したい場合には、[ファイル]のアイコンをクリックすればクイックビュー可能です。

※注意
Google ColaboratoryはGoogle Driveから入りましたが、
ここでの`ファイル`はDrive上とは別です。（上で確認できるディレクトリ構造にはDriveが表示されません、初期状態では。）
ColaboratoryからDriveにアクセスするためには、Driveをマウントする必要があります。
Driveのマウント方法について詳しく知りたい方は別記事を参照ください。
（今回紹介するプログラムにも内包しています。）

#ソースコードの概要
今回作成する最終的なソースコードは最後に記載しています。
以下では順に各セクションの説明をします。
##ライブラリのインポート等
Google Colaboratoryでは主要なpythonライブラリをローカル環境にインストールすることなく使用できます。
また、Google Driveをマウントすることで出力先としてgoogle driveを指定できるため、今回は出力先をGoogle Drive内としています。
※Colaboratory（先に紹介した`ファイル`）内に出力することもできます。デフォルトでは`/contents`がカレントディレクトリになっています。

```python
### Import libraries ###
from google.colab import drive
from datetime import datetime
import numpy as np
import pandas as pd
import time
import os

drive.mount('/content/drive')
```

##出力設定
取得したデータの出力先を指定します。
今回は`MyDrive（日本語表記ではマイドライブ）`内にdataというディレクトリを用意して、
さらにその下にpointというディレクトリを作成した上で、ここに出力しようと思います。
（取得ファイルfは、`マイドライブ/data/point/*`として保存される。）

まずは出力先のディレクトリ`odir`を用意します。

```python
odir = `data/point`
```

次に`odir` を実際に`MyDrive`配下に作成します。
デフォルトでは`Colaboratory:/contents`にいるため、
（Driveをマウントした状態で）`MyDrive`に移動する必要があります。
また、既に同じ名前のディレクトリがあった場合には、そのディレクトリをそのまま使用するようにしています。

```python
## prepare the folder
%cd '/content/drive/MyDrive'
cdir = os.getcwd()
ddir = str(cdir) + '/' + odir
print(ddir)
if not os.path.exists(ddir): os.makedirs(ddir)
```

また、今回使用するpandasライブラリの出力設定も少し。
（10分値×24時間=144行なので、余裕をもって150。）

```python
pd.set_option('display.max_rows',150)
```

##スクレイピングの準備
今回はAMeDASの10分値を対象とするので、そのURLについて調べます。
http://www.data.jma.go.jp/obd/stats/etrn/index.php
上記URLから任意の都府県・地方、地点、年月日を指定し、`10分ごとの値を表示`へと進むと、以下のURLに移動します。
http://www.data.jma.go.jp/obd/stats/etrn/view/10min_a1.php?prec_no=44&block_no=1002&year=2020&month=1&day=1&view=
（ここでは東京都、練馬、2021年1月1日を指定）

`10min_`の後ろが観測区分情報で、`a1`がアメダス、`s1`が気象台・測候所等を表します（練馬はアメダス区分）。
`prec_no`が都府県・地方情報で、2桁の数字で表されます。（練馬であれば「東京」の44）
`block_no`が地点情報で、4~5桁の数字で表されます。（練馬であれば1002）
※1000未満の場合は0埋めが必要。（例：0366, 八王子）
`year=`、`month=`、`day=`はそれぞれ年月日情報です。

つまり、以上の4情報（type, prec, block, date）があれば、URLを作成することが出来ます。
ここでは、一回の実行で複数地点を順に取り込めるようにするために、
これら4情報をそれぞれ配列として設定します。
（参考のために府中を追加し、対象日として2021年1月1日も追加。）
尚、各地点の地点番号等は、以下のページにまとめてあります。
https://script.google.com/macros/s/AKfycbxBEzysNCssxGOBLsI93SqwpPxdTFpRgvVvdFUvujkfBXX12cQ/exec
（Ctrl+Fで検索をかけると効率的かと思います。）

```python
### Scraping Setting ###
pname=['Nerima','Fuchu']
pprec=['44'    ,'44'   ]
pblck=['1002'  ,'1133' ]
pflag=['0'     ,'0'    ]
# Target date (with 8-digit yyyymodd)
dlist=['20200101','20210101']
```
このセッティングでは、「練馬と府中の両地点で2020年1月1日と2021年1月1日の気象データを取得する」ことになっています。
あとは`pprec`等で設定した値をURLに埋め込めば対象のwebページに直接アクセスすることが出来ます。

```python
## extraction date info
for k in dlist: # LOOP with Date
 year = k[0:4]  # year from dlist
 month = k[4:6] # month from dlist
 day = k[6:8]   # day fromt dlist
 dtag = k       # date(tag) fromt dlist

## combine point info
 for f, j, i, n in zip(pflag, pprec, pblck, pname): # LOOP with Points
  flag = f
  prec = j
  blck = i
  name = n

  ## URL
  if flag == '0':
   url = 'http://www.data.jma.go.jp/obd/stats/etrn/view/10min_a1.php?'\
         'prec_no=' + str(prec) + '&block_no=' + str(blck) + \
         '&year=' + str(year) + '&month=' + str(month) + '&day=' + str(day) + '&view=p1'
  else:
   url = 'http://www.data.jma.go.jp/obd/stats/etrn/view/10min_s1.php?'\
         'prec_no=' + str(prec) + '&block_no=' + str(blck) + \
         '&year=' + str(year) + '&month=' + str(month) + '&day=' + str(day) + '&view=p1'
```
以上で今回のスクレイピングの対象となるURLの作成が完了しました。

##スクレイピング
スクレイピング自体は非常に簡潔に書けます。
対象の`utl`のページ内の`Table`をデータフレーム`df`に格納します。
尚、連続してアクセスするとサーバーに余計な負荷をかけてしまうので、
毎アクセスに5秒以上の時間間隔を設定しています。

```python
  ## scraping
  tables = pd.io.html.read_html(url)
  df = tables[0].iloc[:,1:] #row&col
  df = df.reset_index(drop = True)

  ## Sleep
  time.sleep(5)
```

##出力
`出力設定`で用意した`ddir`にスクレイピングで獲得したデータをテキスト形式で出力します。
尚、ここではファイル名`ofile`を地点名AMeDASyyyymodd.txtとしています。

```python
  ## Output
  ofile = str(ddir) + '/' + str(name) + 'AMeDAS' + str(dtag) + '.txt'
  with open(ofile,'w') as f:
   print('This file was downloaded at: ', datetime.now(), '(in UTC)', file=f)
   print('*time* 0 = 00:10 and 143 = 24:00', file=f)
   print('point: ', str(name), file=f)
   print('date:  ', str(dtag), file=f)
   print('URL:   ', str(url), file=f)
   print('', file=f)
   print(df, file=f)
```
以上で出力が完了します。
あとは地点・日時でループをまわすだけです。

#ソースコード
以上の各セクションを結合したものが以下のソースコードです。
コピーしてGoogle Colaboratoryにペースト・実行すればすぐにデータを取得できます。

```python
###++++++++++++++++++++++++++++++++++++++++++###
### Creater: kogetaenoki on 2019/05/18       ###
###++++++++++++++++++++++++++++++++++++++++++###
### reference: https://met-learner.hatenablog.jp/entry/2019/12/15/123637
###+++++

### Import Libraries ###
from google.colab import drive
from datetime import datetime
import numpy as np
import pandas as pd
import time
import os

### Mount own drive ###
# Your permission are required when 1st time
#  after the 1st time, add "#" to head of following command, available.
#  (Nothing wrong with not doing it)
drive.mount('/content/drive')

### output folder name ###
# MyDrive/"odir"
odir = 'data/point'

### output option ###
pd.set_option('display.max_rows',150)

### Scraping Setting ###
pname=['Nerima','Fuchu'] #Site name
pprec=['44'    ,'44'   ] #Area No.
pblck=['1002'  ,'1133' ] #Site No.
pflag=['0'     ,'0'    ] #Site type
# Target date (with 8-digit yyyymodd)
dlist=['20200101','20210101']

###============================###
### Hereafter, DO NOT DISTURB! ###
###============================###

## prepare the folder
%cd '/content/drive/MyDrive'
cdir = os.getcwd()
ddir = str(cdir) + '/' + odir
print(ddir)
if not os.path.exists(ddir): os.makedirs(ddir)

## extraction date info
for k in dlist: # LOOP with Date
 year = k[0:4]  # year from dlist
 month = k[4:6] # month from dlist
 day = k[6:8]   # day fromt dlist
 dtag = k       # date(tag) fromt dlist
 print ('get_data: ',year,'/',month,'/',day)

## combine point info
 for f, j, i, n in zip(pflag, pprec, pblck, pname): # LOOP with Points
  flag = f
  prec = j
  blck = i
  name = n

  ## URL
  if flag == '0':
   url = 'http://www.data.jma.go.jp/obd/stats/etrn/view/10min_a1.php?'\
         'prec_no=' + str(prec) + '&block_no=' + str(blck) + \
         '&year=' + str(year) + '&month=' + str(month) + '&day=' + str(day) + '&view=p1'
  else:
   url = 'http://www.data.jma.go.jp/obd/stats/etrn/view/10min_s1.php?'\
         'prec_no=' + str(prec) + '&block_no=' + str(blck) + \
         '&year=' + str(year) + '&month=' + str(month) + '&day=' + str(day) + '&view=p1'

  print ('point: ', name, ', date: ', dtag)

  ## scraping
  tables = pd.io.html.read_html(url)
  df = tables[0].iloc[:,1:] #row&col
  df = df.reset_index(drop = True)

  ## col_name
  if flag == '0':
   df.columns = ['PRC','TEMP','WS_MEAN','WD_MEAN','WS_GUST','WD_GUST','SUN']
  else:
   df.columns = ['PRES','SLP','PRC','TEMP','RH','WS_MEAN','WD_MEAN','WS_GUST','WD_GUST','SUN']

  ## Sleep
  time.sleep(1)

  ## Output
  ofile = str(ddir) + '/' + str(name) + 'AMeDAS' + str(dtag) + '.txt'
  with open(ofile,'w') as f:
   print('This file was downloaded at: ', datetime.now(), '(in UTC)', file=f)
   print('*time* 0 = 00:10 and 143 = 24:00', file=f)
   print('point: ', str(name), file=f)
   print('date:  ', str(dtag), file=f)
   print('URL:   ', str(url), file=f)
   print('', file=f)
   print(df, file=f)

print ('Done all.')
```




#参考
はじめての気象データ処理（met_learner様）, 気象庁アメダス10分間値をダウンロードする方法, https://met-learner.hatenablog.jp/entry/2019/12/15/123637