Selenium＋Pythonでデータ取得を自動化し、BigQueryに連携した話（後編）

# はじめに

こんにちは、京セラコミュニケーションシステム　西田（@kccs_hiromi-nishida）です。
今回は前編に続いて、後編の記事となります！

https://qiita.com/kccs_hiromi-nishida/items/587b41dc6a4b766b73ea

たとえば基幹システム等の既存システムから何かデータを取得・連携して分析したいと思っても、費用対効果もわからないうちから正式にデータ連携出力を依頼するのはハードルが少し高いな・・と思ったことはありませんか？

そんな時、まずはスクレイピングで気軽に試してみるのもよいかもしれません。

前編、後編を合わせて読んでいただくことで、スクレイピングからデータ連携・分析までの一連の流れを確認できますので、ぜひ両編とも目を通して頂ければと思います。
そして、この記事が業務改善の一助になれれば幸いです！

:::note warn
本記事は2022年12月ごろに作成しております。よって、引用している文章などはこの時点での最新となります。ご了承ください。
:::

## この記事の対象者

- WEBサイトからのデータ収集を自動化してみたいと思っている方
- Pythonを使ったスクレイピングに興味のある方
- CSVデータをBigQueryに連携し、分析してみたい方

## 今回の記事の範囲

前回の記事ではSelenium+Pythonを使ってWEBサイトからデータを自動収集してCSVファイル出力するところをご紹介しました。

今回の記事範囲は出力したCSVファイルをCloud Storage APIを使ってCloud Storageにアップロードし、BigQueryから外部テーブルでCloud Storage上のCSVファイルを参照、そのデータをコネクテッドシートで分析するところ（下図のオレンジ枠の範囲）となります！

![img12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2752159/3c791685-f9b9-5560-7a10-74037971167e.png)

## 前提

前編記事からの続きとなる記事ですので、[前編記事の前提](https://qiita.com/kccs_hiromi-nishida/items/587b41dc6a4b766b73ea#%E5%89%8D%E6%8F%90B "前編-前提")もそのまま引き継いでいます。

また、Cloud Storage、BigQueryを利用しますので、Google Cloudの利用開始がまだの方は以下サイトより利用登録を行うことができますので、利用を開始しておいてください。

:::note info
［参照］公式サイト・ドキュメント
  [無料トライアルと無料枠](https://cloud.google.com/free)</br>
　　上記サイトの「無料で開始」ボタンから登録が可能
  [Google Cloud の無料プログラム](https://cloud.google.com/free/docs/free-cloud-features)
　　Google Cloudの無料プログラムの詳細を確認できます
:::

## Cloud Storage APIを使えるようにする

PythonからCloud Storageの操作を行うために、今回はCloud Storage APIを使います。
順を追って利用方法を説明します。

### サービスアカウントの作成

:::note warn
使用画像について
特別な記載のない限り、画像はGoogle Cloud - IAMと管理画面をキャプチャしたものとなります
:::

サービスアカウント[^1]とはプログラムからGoogle APIへアクセスするために使用される特殊なGoogleアカウントです。
今回、PythonプログラムからCloud Storage APIを使用するため、まずサービスアカウントの作成が必要となります。

Google Cloudにアクセスしてハンバーガーメニューを開き、IAMと管理 ⇒ サービスアカウントを選択します。
<img width="400" alt="サービスアカウントの開き方" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2752159/51618687-661f-4383-c9bd-693adce8a3c5.png">
画面上部の［サービスアカウントを作成］を選択してください。
<img width="400" alt="サービスアカウントの開き方" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2752159/6580de31-f2fb-abed-721d-ffd0185613b6.png">
サービスアカウント名とサービスアカウントの説明を入力し、［作成して続行］を選択してください。
<img width="400" alt="サービスアカウント作成1" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2752159/415bce78-68b1-4e66-e877-ebb1e73ee322.png">
［ロールを追加］を選択し、Cloud Storage ⇒ ストレージ管理者を選択し、［完了］を選択してください。これでサービスアカウントの作成は完了です。
<img width="300" alt="サービスアカウント作成2" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2752159/5406dfbd-83ba-9072-1264-00daca59236b.png">　<img width="300" alt="サービスアカウント作成3" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2752159/3d65dc9f-d139-3625-e38a-26770c69b141.png">

### サービスアカウントキーの作成

次に作成したサービスアカウントのキーを作成します。
※このキーを使って認証を行います。

先ほど作成したサービスアカウントを選択します。
<img width="400" alt="作成したサービスアカウント" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2752159/e3cba813-416d-13c7-eb29-0286d96839cb.png">
［キー］を選択し、［鍵を追加］⇒［新しい鍵を作成］を選択してください。
<img width="400" alt="キー作成1" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2752159/a0f7b354-f753-1ec4-dd2e-b7c1547edaa8.png">
[JSON]を選択し、［作成］を選択すると、キーが自動的にダウンロードされます。
<img width="300" alt="キー作成2" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2752159/877d9470-c6ab-5df2-2a70-6d0b1bbdca7e.png">
このキーをわかりやすい場所に移動させておきましょう。
<img width="400" alt="キー配置" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2752159/b487cd1d-eb6c-22de-128a-e31596bddbc5.png">
※私の場合は、sample.py（[前編](https://qiita.com/kccs_hiromi-nishida/items/587b41dc6a4b766b73ea "前編記事")で作成したプログラム）と同じ階層に配置し、わかりやすい名前にリネームしました（storage_key.json）

## Google Cloud Storage用のライブラリをインストール

Python用のGoogle Cloud Storageのライブラリをインストールします。

コマンドプロンプト（Macの方はターミナル）を起動して以下を入力するだけでインストールが完了します。

```console:インストールコマンド
pip install google-cloud-storage
```
### Cloud Storageにバケットを作成

:::note warn
使用画像について
特別な記載のない限り、画像はGoogle Cloud - Cloud Storage画面をキャプチャしたものとなります
:::

早速プログラミング！といきたいところですが、その前にCSVファイルをアップロードするバケットをCloud Storageに作成しておく必要があるので、作成しておきます。

Google Cloudにアクセスしてハンバーガーメニューを開き、Cloud Storage ⇒ バケットを選択します。
<img width="400" alt="Cloud Storage-バケット" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2752159/dc68a3e9-ca27-1c8b-7ac0-ca8f7ea12dae.png">
画面上部の［作成］を選択してください。
<img width="400" alt="Cloud Storage-バケット" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2752159/cba4af4f-6e36-526c-7d1b-b1348f7a73f1.png">
バケットの名前を入力し、［続行］を選択してください。
<img width="400" alt="Cloud Storage-バケット作成画面1" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2752159/52ea2b68-5114-0664-415d-56969a9a087a.png">
ロケーションタイプは今回Regionとし、asia-northeast1を選択しました。
［続行］を選択してください。
<img width="400" alt="Cloud Storage-バケット作成画面2" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2752159/f1cc04de-9a10-c23b-0fb4-5a72ed7c3600.png">
後の項目はとくに変更の必要はないので、［続行］を選択していき、最後［作成］を選択してください。バケットが作成されました。
<img width="400" alt="Cloud Storage-バケット作成画面2" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2752159/b3fd5fda-a263-f903-db64-5253032ac007.png">

## PythonからCloud Storageにファイルをアップロード

では、[前編-CSVファイルを出力する](https://qiita.com/kccs_hiromi-nishida/items/587b41dc6a4b766b73ea#csv%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%82%92%E5%87%BA%E5%8A%9B%E3%81%99%E3%82%8B "前編-CSVファイルを出力する")からの続きに、順を追って記述していきましょう！ 

まずは、必要なモジュールをインポートします。

```python:sample.py
# 冒頭部分に追記してください
from google.cloud import storage
```

次にサービスアカウントキーを使って認証を行い、バケットを取得します。

```python:sample.py
# 保管したサービスアカウントキーを指定します
client = storage.Client.from_service_account_json("storage_key.json")
# 作成したCSVファイルアップロード先バケット名を指定します
bucket = client.get_bucket("sample_csv_upload_bucket")
```

バケットを取得できたら、そのバケットにCSVファイルをアップロードします。

```python:sample.py
blob = bucket.blob(file_name)
blob.upload_from_filename(output_path)
```

ここまで記述できたら、sample.pyを実行してみてください。
指定したバケットにCSVファイルがアップロードされているはずです。
<img width="400" alt="Cloud Storage-バケット画面" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2752159/c1f5f20b-4edc-b246-68f4-4bb5b3a1e947.png">

## Cloud Storage上のCSVファイルをBigQueryのテーブルに読み込んでみよう

:::note warn
使用画像について
特別な記載のない限り、画像はGoogle Cloud - BigQuery画面をキャプチャしたものとなります
:::

まず、BigQureyにデータセットを作成し、作成したデータセット内にテーブルを作成します。

### データセットを作成する

Google Cloudにアクセスしてハンバーガーメニューを開き、BigQuery ⇒ SQLワークスペースを選択します。
<img width="400" alt="BigQuery画面" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2752159/bd504727-cc2a-6708-ef7e-e89e207175e3.png">
データセットを作成するプロジェクトを選択 ⇒ データセットを作成を選択します。
これでデータセットの作成は完了です。
<img width="400" alt="BigQuery画面" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2752159/da32bce6-de28-2381-e886-cdafdd754ee8.png">
データセットIDを入力し、データのロケーションにはasia-northeast1を選択し、［データセットを作成］を選択してください。
※作成したCloud Storageのバケットのロケーションと合わせておいてください
<img width="400" alt="データセット作成画面" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2752159/66920d38-1f84-b338-d60a-62c810793108.png">

### 作成したデータセットにテーブルを作成する

作成したデータセットを選択 ⇒ テーブルを作成を選択します。
<img width="400" alt="テーブル作成画面1" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2752159/cd2f20c9-1851-b38a-7e5c-079a1169c9d0.png">
テーブルの作成元にはGoogle Cloud Storageを選択してください。
選択すると、バケットからファイルを選択するための参照ボタンが表示されるので、［参照］ボタンを選択します。
<img width="400" alt="テーブル作成画面2" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2752159/e004e31b-0495-1747-5c6c-b544528c950a.png">
バケットを選択 ⇒ CSVファイルを選択して、画面下部の選択ボタンを押下してください。
<img width="300" alt="テーブル作成画面3" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2752159/ac9a4c75-2eb9-a942-2d49-1ac8a43a47cd.png">　<img width="300" alt="テーブル作成画面3" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2752159/5af8afdf-e276-16ff-7da7-bdf8fbb44026.png">
テーブル名を入力し、テーブルタイプは［外部テーブル］を選択してください。
<img width="400" alt="テーブル作成画面4" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2752159/e4916de7-b7ca-cc89-9134-53bb4e039fb5.png">

スキーマは、［テキストとして編集］をONにすると、入力できる状態になるので、
<img width="400" alt="テーブル作成画面5" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2752159/043d40d6-fabd-0e75-c4b5-81626d8b2a9d.png">
以下のスキーマ定義を貼り付けてください。
※長いので折りたたんでいます。クリックすると展開します。

<details><summary>スキーマ定義</summary><div>

```json:スキーマ定義
[
  {
    "mode": "NULLABLE",
    "name": "year",
    "type": "STRING",
    "description": "年"
  },
  {
    "mode": "NULLABLE",
    "name": "atm_p_local_ave",
    "type": "STRING",
    "description": "気圧_現地_平均"
  },
  {
    "mode": "NULLABLE",
    "name": "atm_p_sea_surf_ave",
    "type": "STRING",
    "description": "気圧_海面_平均"
  },
  {
    "mode": "NULLABLE",
    "name": "precipitation_total",
    "type": "STRING",
    "description": "降水量_合計"
  },
  {
    "mode": "NULLABLE",
    "name": "precipitation_max_day",
    "type": "STRING",
    "description": "降水量_最大_日"
  },
  {
    "mode": "NULLABLE",
    "name": "precipitation_max_hour",
    "type": "STRING",
    "description": "降水量_最大_1時間"
  },
  {
    "mode": "NULLABLE",
    "name": "precipitation_max_min",
    "type": "STRING",
    "description": "降水量_最大_10分間"
  },
  {
    "mode": "NULLABLE",
    "name": "temp_ave_daily_avg",
    "type": "STRING",
    "description": "気温_平均_日平均"
  },
  {
    "mode": "NULLABLE",
    "name": "temp_ave_daily_high",
    "type": "STRING",
    "description": "気温_平均_日最高"
  },
  {
    "mode": "NULLABLE",
    "name": "temp_ave_daily_min",
    "type": "STRING",
    "description": "気温_平均_日最低"
  },
  {
    "mode": "NULLABLE",
    "name": "temp_highest",
    "type": "STRING",
    "description": "気温_最高"
  },
  {
    "mode": "NULLABLE",
    "name": "temp_lowest",
    "type": "STRING",
    "description": "気温_最低"
  },
  {
    "mode": "NULLABLE",
    "name": "hum_avg",
    "type": "STRING",
    "description": "湿度_平均"
  },
  {
    "mode": "NULLABLE",
    "name": "hum_min",
    "type": "STRING",
    "description": "湿度_最小"
  },
  {
    "mode": "NULLABLE",
    "name": "wind_dir_speed_avg_wind_speed",
    "type": "STRING",
    "description": "風向・風速_平均風速"
  },
  {
    "mode": "NULLABLE",
    "name": "wind_dir_speed_max_wind_speed",
    "type": "STRING",
    "description": "風向・風速_最大風速_風速"
  },
  {
    "mode": "NULLABLE",
    "name": "wind_dir_speed_max_wind_dir",
    "type": "STRING",
    "description": "風向・風速_最大風速_風向"
  },
  {
    "mode": "NULLABLE",
    "name": "wind_dir_speed_max_inst_wind_speed",
    "type": "STRING",
    "description": "風向・風速_最大瞬間風速_風速"
  },
  {
    "mode": "NULLABLE",
    "name": "wind_dir_speed_max_inst_wind_dir",
    "type": "STRING",
    "description": "風向・風速_最大瞬間風速_風向"
  },
  {
    "mode": "NULLABLE",
    "name": "sunlight_hours",
    "type": "STRING",
    "description": "日照時間"
  },
  {
    "mode": "NULLABLE",
    "name": "solar_radiation_day_avg",
    "type": "STRING",
    "description": "全天日射量平均"
  },
  {
    "mode": "NULLABLE",
    "name": "snow_snowfall_total",
    "type": "STRING",
    "description": "雪_降雪_合計"
  },
  {
    "mode": "NULLABLE",
    "name": "snow_snowfall_max_day_total",
    "type": "STRING",
    "description": "雪_降雪_日合計の最大"
  },
  {
    "mode": "NULLABLE",
    "name": "snow_deepest_snow",
    "type": "STRING",
    "description": "最深積雪"
  },
  {
    "mode": "NULLABLE",
    "name": "cloud_cover_avg",
    "type": "STRING",
    "description": "雲量平均"
  },
  {
    "mode": "NULLABLE",
    "name": "atm_phenomenon_num_of_snow_days",
    "type": "STRING",
    "description": "大気現象_雪日数"
  },
  {
    "mode": "NULLABLE",
    "name": "atm_phenomenon_fog_days",
    "type": "STRING",
    "description": "大気現象_霧日数"
  },
  {
    "mode": "NULLABLE",
    "name": "atm_phenomenon_thunder_days",
    "type": "STRING",
    "description": "大気現象_雷日数"
  }
]
```

</div></details>

詳細オプションを開き、スキップするヘッダー行に［1］を入力し、［テーブルを作成］ボタンを選択してください。
<img width="400" alt="テーブル作成画面6" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2752159/3bfea0d0-460d-8e32-b21f-cff24542b041.png">
テーブル作成が完了しました。
<img width="400" alt="テーブル作成画面7" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2752159/57179521-41c6-0ed6-95e2-de9d188183ed.png">

### データを加工してViewを作る

今回の気象データの中には、よーく見ると数値だけではなく記号[^2]も含まれています。

その為、今回テーブルのスキーマ定義で項目の方はすべて文字列型（STRING）にしました。
ですが、データを使って分析する際に、数値型でないとグラフなどを作成するのが難しくなります。
そこで文字列型を数値型（NUMERIC）に変換したViewを作成し、分析時はこのViewをインプットにしたいと思います。

作成したテーブルを選択し、クエリ ⇒ 新しいタブを選択してください。
<img width="400" alt="View作成1" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2752159/a2ab08aa-b9a0-aaea-9088-4a4b0c8eaade.png">
画面が開いたら、以下のSQL文を貼り付けて、保存 ⇒ ビューを保存を選択してください。
<img width="400" alt="View作成2" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2752159/2865aa0e-5e74-202b-4ab0-638974dc7bba.png">
※長いので折りたたんでいます。クリックすると展開します。
※SQL中の「★プロジェクト名★」は使用しているプロジェクト名に置き換えてください。
<details><summary>View作成用SQL</summary><div>

```sql:View作成用SQL
SELECT
  SAFE_CAST(`year` AS NUMERIC) AS `year`,
  SAFE_CAST(`atm_p_local_ave` AS NUMERIC) AS `atm_p_local_ave`,
  SAFE_CAST(`atm_p_sea_surf_ave` AS NUMERIC) AS `atm_p_sea_surf_ave`,
  SAFE_CAST(`precipitation_total` AS NUMERIC) AS `precipitation_total`,
  SAFE_CAST(`precipitation_max_day` AS NUMERIC) AS `precipitation_max_day`,
  SAFE_CAST(`precipitation_max_hour` AS NUMERIC) AS `precipitation_max_hour`,
  SAFE_CAST(`precipitation_max_min` AS NUMERIC) AS `precipitation_max_min`,
  SAFE_CAST(`temp_ave_daily_avg` AS NUMERIC) AS `temp_ave_daily_avg`,
  SAFE_CAST(`temp_ave_daily_high` AS NUMERIC) AS `temp_ave_daily_high`,
  SAFE_CAST(`temp_ave_daily_min` AS NUMERIC) AS `temp_ave_daily_min`,
  SAFE_CAST(`temp_highest` AS NUMERIC) AS `temp_highest`,
  SAFE_CAST(`temp_lowest` AS NUMERIC) AS `temp_lowest`,
  SAFE_CAST(`hum_avg` AS NUMERIC) AS `hum_avg`,
  SAFE_CAST(`hum_min` AS NUMERIC) AS `hum_min`,
  SAFE_CAST(`wind_dir_speed_avg_wind_speed` AS NUMERIC) AS `wind_dir_speed_avg_wind_speed`,
  SAFE_CAST(`wind_dir_speed_max_wind_speed` AS NUMERIC) AS `wind_dir_speed_max_wind_speed`,
  SAFE_CAST(`wind_dir_speed_max_wind_dir` AS NUMERIC) AS `wind_dir_speed_max_wind_dir`,
  SAFE_CAST(`wind_dir_speed_max_inst_wind_speed` AS NUMERIC) AS `wind_dir_speed_max_inst_wind_speed`,
  SAFE_CAST(`wind_dir_speed_max_inst_wind_dir` AS NUMERIC) AS `wind_dir_speed_max_inst_wind_dir`,
  SAFE_CAST(`sunlight_hours` AS NUMERIC) AS `sunlight_hours`,
  SAFE_CAST(`solar_radiation_day_avg` AS NUMERIC) AS `solar_radiation_day_avg`,
  SAFE_CAST(`snow_snowfall_total` AS NUMERIC) AS `snow_snowfall_total`,
  SAFE_CAST(`snow_snowfall_max_day_total` AS NUMERIC) AS `snow_snowfall_max_day_total`,
  SAFE_CAST(`snow_deepest_snow` AS NUMERIC) AS `snow_deepest_snow`,
  SAFE_CAST(`cloud_cover_avg` AS NUMERIC) AS `cloud_cover_avg`,
  SAFE_CAST(`atm_phenomenon_num_of_snow_days` AS NUMERIC) AS `atm_phenomenon_num_of_snow_days`,
  SAFE_CAST(`atm_phenomenon_fog_days` AS NUMERIC) AS `atm_phenomenon_fog_days`,
  SAFE_CAST(`atm_phenomenon_thunder_days` AS NUMERIC) AS `atm_phenomenon_thunder_days`
FROM 
    `★プロジェクト名★.weather_dataset.tokyo_data`
```

</div></details>

データセットを選択し、テーブル名を入力して保存を選択してください。
これでViewの作成は完了です。
<img width="400" alt="View作成3" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2752159/4f28e0a3-fbf3-424f-fdf0-7110de242687.png">

## コネクテッドシートでデータを見てみよう

BigQueryにデータを取り込むことができたので、さっそくコネクテッドシートでデータを見てみましょう。
コネクテッドシートに関しては以前記事投稿していますので、合わせてみて頂ければ嬉しいです！

https://qiita.com/kccs_hiromi-nishida/items/fe33f23ff6fdd896acdb

:::note warn
使用画像について
特別な記載のない限り、画像はGoogleスプレッドシート画面をキャプチャしたものとなります
:::

### BigQueryに接続して、スプレッドシート上にデータを表示する

スプレッドシートを新規作成し、データ → データコネクタ → BigQueryに接続を選択します。
<img width="400" alt="接続" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2752159/fc7c8596-2ab2-798c-e1a7-a4d2018a677b.png">
プロジェクトを選択します。
<img width="400" alt="プロジェクト選択" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2752159/567f5c52-a9dd-4ad7-ef74-89050879e2d2.png">

データセットを選択し、tokyo_data_viewを選択し接続ボタンを押下してください。
<img width="300" alt="データセット選択" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2752159/1880eedb-b6d7-d212-b51a-0f35df1a9001.png">　<img width="300" alt="ビュー選択" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2752159/b23b4061-bfd6-180b-2ada-435b26598506.png">
スプレッドシート上でデータを見ることができるようになりました！
<img width="400" alt="データ画面" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2752159/0573d4de-dd61-58ab-10b3-36e224c2f17b.png">

### グラフを作ってみる

では、試しにグラフを作ってみましょう。シートの［グラフ］を選択してください。
<img width="400" alt="グラフ作成" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2752159/d9a6d482-01fc-488e-2e3f-e33029d703fb.png">
新しいシートを選択し、作成ボタンを押下します。
<img width="300" alt="グラフ作成" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2752159/f18acb74-3102-f53b-e48d-607ce07285f8.png">
今回は、年別の最高気温と最低気温の推移がわかるグラフを作ってみようと思います。
グラフエディタで、画像のように設定を行います。

● グラフの種類：縦棒グラフ
● X軸：year
● 系列：temp_highestとtemp_lowest
● フィルタ：temp_highestとtemp_lowestそれぞれ空白ではない値
<img width="300" alt="グラフ作成" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2752159/88d1a5af-9d7f-6926-fedf-a617a5f98659.png"> <img width="300" alt="グラフ作成" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2752159/343af15f-a3e0-7272-9538-dcf0703b1c9e.png">
ここまで設定したら、適用ボタンを押下してください。
グラフが表示されました！
<img width="400" alt="グラフ作成" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2752159/5b31e7e0-9079-ed52-04fe-2ec7fcfa5725.png">
あとは、グラフのタイトルや凡例を変更して、こんな感じにしてみました。
こうみると、最高気温・最低気温が徐々に上昇していることがわかります。
とくに最低気温！昔の東京ってすごく寒かったんですね！
<img width="400" alt="グラフ作成" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2752159/0a56ce03-6445-fd3d-b3ac-96822bf3b76d.png">
グラフ以外にもピボットテーブルを作成したり、データの抽出もできるのでコネクテッドシートを使って色々な分析をしてみてください！

## まとめ

+ SeleniumはWEBブラウザの自動化（スクレイピング）を行える便利なツール！
+ スクレイピングには注意点があるのでよく確認すること（[前編記事：スクレイピングの注意点](https://qiita.com/kccs_hiromi-nishida/items/587b41dc6a4b766b73ea#%E3%82%B9%E3%82%AF%E3%83%AC%E3%82%A4%E3%83%94%E3%83%B3%E3%82%B0%E3%81%AE%E6%B3%A8%E6%84%8F%E7%82%B9B "[前編記事：スクレイピングの注意点")）
+ Cloud Storage APIを使えば、プログラムからCloud Storageの操作が可能
+ BigQueryにデータがあれば、色んなツールで分析ができる！（手軽に始めるならコネクテッドシート）

## おまけ

今回作成したsample.pyですが、記事上では説明の為、ソースコードを細切れで掲載しました。
ここにソースコードをまとめて掲載しておきます。
※長いので折りたたんでいます。クリックすると展開します。

<details><summary>完成版プログラムコード</summary><div>

```python:sample.py
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager
from google.cloud import storage
import pandas as pd

# 使用しているChromeブラウザのバージョンにあったDriverがインストールされます
# バージョンに相違がない場合はインストールされません
chrome_service = Service(ChromeDriverManager().install())

# Driverのオプションを指定できます
options = webdriver.ChromeOptions()
options.add_experimental_option('excludeSwitches', ['enable-logging'])
options.use_chromium = True
options.add_argument("--headless")  # 最初はコメントアウトしておいてもOKです
driver = webdriver.Chrome(service=chrome_service, options=options)
# 要素がロードされるまでの待ち時間を10秒に設定します
driver.implicitly_wait(10)

# 取得したいWEBサイトのURLを指定します(今回は気象庁-過去の気象データ検索画面のURL)
driver.get("https://www.data.jma.go.jp/obd/stats/etrn/")

# 都府県・地方選択画面を表示
area_link = driver.find_element(
    By.XPATH, '//*[@id="main"]/table[4]/tbody/tr/td[1]/div/table/tbody/tr[2]/td/a')
driver.execute_script('arguments[0].click();', area_link)

# 地図の中から東京都を選択
select_area_link = driver.find_element(
    By.XPATH, '//*[@id="main"]/map/area[25]')
driver.execute_script('arguments[0].click();', select_area_link)

# 東京都のエリアから東京を選択
select_tokyo = driver.find_element(
    By.XPATH, '//*[@id="ncontents2"]/map/area[9]')
driver.execute_script('arguments[0].click();', select_tokyo)

# 年ごとの値を選択
select_year = driver.find_element(
    By.XPATH, '//*[@id="main"]/table[4]/tbody/tr/td[3]/div/table/tbody/tr[1]/td[1]/table/tbody/tr[1]/td[2]/a')
driver.execute_script('arguments[0].click();', select_year)

# 表全体を取得
table = driver.find_element(By.XPATH, '//*[@id="tablefix1"]')
html = table.get_attribute('outerHTML')
df_temp_data = pd.read_html(html)

# CSVヘッダーの定義
header_columns = ["年", "気圧_現地_平均", "気圧_海面_平均", "降水量_合計", "降水量_最大_日", "降水量_最大_1時間",
                  "降水量_最大_10分間", "気温_平均_日平均", "気温_平均_日最高", "気温_平均_日最低", "気温_最高",
                  "気温_最低", "湿度_平均", "湿度_最小", "風向・風速_平均風速", "風向・風速_最大風速_風速",
                  "風向・風速_最大風速_風向", "風向・風速_最大瞬間風速_風速", "風向・風速_最大瞬間風速_風向",
                  "日照時間", "全天日射量平均", "雪_降雪_合計", "雪_降雪_日合計の最大", "最深積雪",
                  "雲量平均", "大気現象_雪日数", "大気現象_霧日数", "大気現象_雷日数"]

output_data = []

# 行を1行ずつ取得
for i, data in df_temp_data[0].iterrows():
    record = []
    # 行から項目数分のデータだけ取得して保持
    for j in range(0, len(header_columns)):
        record.append(data[j])
    output_data.append(record)

# CSV出力用のDataFrameを定義
output_df = pd.DataFrame(data=output_data, columns=header_columns)

file_name = "tokyo_weather_data.csv"
# output_pathはどこでも構いませんが、今回はsample.pyと同じ階層に
# outputフォルダを作成しておき、そのフォルダに出力するようにしました
output_path = "./output/" + file_name
output_df.to_csv(output_path, index=False, encoding="shift-jis")

# Chrome Driverのclose処理
driver.close()

# Cloud Storageにファイルをアップロードする
client = storage.Client.from_service_account_json(
    'storage_key.json')
bucket = client.get_bucket("sample_csv_upload_bucket")

# CSVファイルをアップロード
blob = bucket.blob(file_name)
blob.upload_from_filename(output_path)
```

</div></details>

[^1]: [サービス アカウントについて](https://cloud.google.com/iam/docs/understanding-service-accounts?hl=ja "サービス アカウントについて") ――公式ドキュメント
[^2]: [値欄の記号の説明](https://www.data.jma.go.jp/obd/stats/data/mdrr/man/remark.html "値欄の記号の説明") ――気象庁