初心者がChatGPT先生とWEB開発（IIS,Python,Athena,S3）その①

# 初めに

AIのお勉強のため、今までやってこなかったWEBシステム（中身スカスカの機能だけ）の開発をChatGPT先生に手ほどきしてもらって実施してみました。
せっかくなので覚えたてのAthenaも使ってみたい。
ということで以下構成を作ることが目標。
**10/24に私のTEC仲間が後編を作成してくれました。**
**（筆不精な私に代わってありがとう！！）**
https://qiita.com/MrTansansui/items/4ac8ab34e98b69d151fb#_reference-590ebfc8f3a289af97c0


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2989873/9646c5a7-421f-d743-bbf2-aa0218690ed4.png)

長いのでまずはAthenaの設定とPythonサーバからAthenaを操作できるようにするところまでを①でやります。
次回②としてPythonサーバでAthenaを操作するところをアプリケーション化するのと、
IISサーバでHTMLを作成するところを実施します。

お詫び：
　タイトルでChatGPT先生を前面に出しているのに、
　S3データ格納とATHENAのデータベース・カラム作成はChatGPT先生のお力を借りずやっちゃってます。
　ご了承ください。

## ①データ格納

S3にバケット作って格納するだけ。
ここはChatGPT先生の力を借りずやっちゃいました。
唯一注意することとして、ちゃんとデータ格納専用のバケットを作成しましょう。
後でAthenaでテーブル定義を作成しますがその時にバケットで指定するので困ります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2989873/b1b00952-7716-bdf3-5f2e-728d28111616.png)


中身はこんな感じ
完全なテスト用サンプルです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2989873/ea5c34c4-3c98-68ea-7924-584c7c48ec71.png)

## ②DB作成、カラム作成
ここではAthenaで①でS3に置いたファイルをテーブル化します。
やることは2つ
　・AWS Glueでデータベースを作成
　・AWS Glueでテーブル定義を作成
はい、見事にGlueばかりですね。
Athenaって言わない方が良いのかなぁ。。。

ここもChatGPT先生に頼らずやっちゃいます。

まずはGlueにアクセスしてAdd databeseでデータベース名を記載してCreateを押します。
そうすればDatabase作成完了です。
注：作成後にこの記事作っているので作成前画面は黒塗りでごめんなさい。
　　~~削除→作成は面倒~~

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2989873/03a30737-2482-d66e-15a5-91c555bbe494.png)

次にテーブル作成します。
GlueでAdd tableを選択して色々設定。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2989873/25efe567-2464-f087-6072-4c3d5bf2a237.png)

databeseは先ほど作成したやつを選択
ファイル形式は適切に選択。（今回はCSVファイルを用意したのでCSV）
他はデフォルトでOK

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2989873/d81ef61f-8abb-638a-cf00-e864616156eb.png)
注意
バケットを指定しファイルを指定しないこと。
怒られます。
（なぜかバケットで指定しても同じエラーで怒られますが不具合？？
　ただバケット指定の場合はちゃんと作成できます）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2989873/c4e52ba6-a540-59a9-0ff3-db31aae3fa2c.png)
次はスキーマを作成。ここではカラム定義のことですね。
パーティション設定もできますが今回は割愛

ここまで作成するとAthenaにテーブルが出てきます。
3点リーダからテーブルをプレビューを選択すると10行表示のSQLが発行されデータが見えた！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2989873/685ebcf2-12a5-93d9-77c3-0506503c0f3e.png)

これでAthenaは完了次に進みます。

## ③SQL発行APP作成(まずは手動操作で出来るまで)
ここからがChatGPT先生の出番です。
EC2にminicondaをインストールしたPython環境があるのでそこで実行するアプリの作成をお願いしてみます。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2989873/4ceac795-29ae-7411-ec5d-6e819066394e.png)
聞いてみたら・・・

~~~
import boto3
import pandas as pd

# AWSの認証情報を設定する
aws_access_key_id = 'your_access_key_id'
aws_secret_access_key = 'your_secret_access_key'
region_name = 'your_region_name'

# Athenaクライアントを作成する
client = boto3.client('athena',
                      aws_access_key_id=aws_access_key_id,
                      aws_secret_access_key=aws_secret_access_key,
                      region_name=region_name)

# クエリを実行する
query_string = 'SELECT * FROM your_database.your_table LIMIT 10'
query_execution = client.start_query_execution(QueryString=query_string,
                                                QueryExecutionContext={
                                                    'Database': 'your_database'
                                                },
                                                ResultConfiguration={
                                                    'OutputLocation': 's3://your-s3-bucket/athena/'
                                                })

# クエリの実行結果を取得する
query_execution_id = query_execution['QueryExecutionId']
query_execution_status = 'RUNNING'
while query_execution_status in ['RUNNING', 'QUEUED']:
    query_execution_status = client.get_query_execution(QueryExecutionId=query_execution_id)['QueryExecution']['Status']['State']
    print('Query Status: {}'.format(query_execution_status))

query_results = client.get_query_results(QueryExecutionId=query_execution_id)

# 結果をPandasのDataFrameに変換する
column_names = [c['Name'] for c in query_results['ResultSet']['ResultSetMetadata']['ColumnInfo']]
rows = [[list(row.values())[i] if i < len(row) else None for i in range(len(column_names))] for row in query_results['ResultSet']['Rows'][1:]]
df = pd.DataFrame(rows, columns=column_names)

print(df.head())

このコードは、以下の手順でAthenaに接続し、クエリを実行して結果を取得しています。

AWSの認証情報を設定する。
boto3を使用してAthenaクライアントを作成する。
クエリを実行する。
クエリの実行結果を取得する。
結果をPandasのDataFrameに変換する。
クエリの実行結果は、PandasのDataFrameとして取得されます。DataFrameには、クエリの実行結果が含まれます。また、結果をCSVファイルとして保存することもできます。
~~~
むっちゃ、ちゃんと出てきた(；ﾟДﾟ)
ってことで早速実行した所、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2989873/788ca227-951f-f1a0-e57c-3ddbbf60b56d.png)

途中で怒られた。。。
アクセスキー情報は出せないのでリージョン情報だけ見せますがどうもここの定義がおかしそう。
ってことで先生お願いします！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2989873/e08ee299-6787-cc10-f7f9-c90c50127cfe.png)

~~~
エラーメッセージから推測される原因は、`aws_access_key_id`と
`aws_secret_access_key`の値にシングルクォートをつけていないため、
構文エラーが発生していることです。
`aws_access_key_id`と`aws_secret_access_key`の値は、
文字列として扱う必要があるため、シングルクォートで囲む必要があります。

以下のように、シングルクォートで囲むことで構文エラーを回避できます。
　もう黒塗りしんどいので例は割愛。。。

また、AWSアクセスキーとシークレットアクセスキーは、セキュリティ上の理由から、
これらのキーをコードに直接書き込むことは推奨されません。
代わりに、AWS CLIまたはIAMロールを使用して、
キーを安全に管理することをお勧めします。
~~~

なんかセキュリティ面での心配までされた。
あなたの指示なんですが。。。

とはいえ改善したので次に進みます

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2989873/9a485842-9b25-0c2d-d60e-7f407d5d162b.png)

またすぐエラー。
助けて～

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2989873/6a8d1599-9833-0a3c-a786-9e8f9998f477.png)

よくわからんのでそのまま聞いてみたら、

~~~
このエラーは、Athenaに対するアクセス権限が不足しているために発生しています。
この場合、IAMユーザーにAthenaに対する必要な権限を付与する必要があります。

具体的には、IAMユーザーに以下のアクセス権限が必要です。

1. `athena:StartQueryExecution`
2. `athena:StopQueryExecution`
3. `athena:GetQueryExecution`
4. `athena:GetQueryResults`
5. `s3:GetObject`
6. `s3:GetBucketLocation`
7. `s3:ListBucket`

これらのアクセス権限をIAMユーザーに付与するには、
IAMコンソールでポリシーを作成し、
IAMユーザーに割り当てる必要があります。
以下は、ポリシーの例です。

```json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "AthenaAccess",
            "Effect": "Allow",
            "Action": [
                "athena:StartQueryExecution",
                "athena:StopQueryExecution",
                "athena:GetQueryExecution",
                "athena:GetQueryResults"
            ],
            "Resource": [
                "arn:aws:athena:ap-northeast-1:123456789012:workgroup/primary",
                "arn:aws:athena:ap-northeast-1:123456789012:workgroup/your-workgroup"
            ]
        },
        {
            "Sid": "S3Access",
            "Effect": "Allow",
            "Action": [
                "s3:GetObject",
                "s3:GetBucketLocation",
                "s3:ListBucket"
            ],
            "Resource": [
                "arn:aws:s3:::your-s3-bucket/*",
                "arn:aws:s3:::your-s3-bucket"
            ]
        }
    ]
}
```

このポリシーでは、Athenaに対する必要なアクセス権限と、
S3に対する必要なアクセス権限が設定されています。
IAMユーザーにこのポリシーを割り当てることで、
Athenaに対するアクセス権限が付与されます。
~~~
 ちゃんと回答くれた。
　IAM権限カスタムを推奨されたけどちょっと面倒なので横着して設定。
(取り合えずfullつけときゃええやろの精神。
　商用環境でこの精神発揮したら袋叩きですね(-_-;))

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2989873/98037df1-5d6d-1f0e-7655-f3ff31bb06e1.png)

とはいえ進めました。
次に行きます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2989873/c07045b5-4452-a6ce-bec5-e50a70f6b726.png)
むむっ、なんか崩れてる。
ちょっとこれだとできたとは言い難いので何とかする方法聞いてみます

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2989873/367e539b-ea41-4342-8ca8-0c25fc72a418.png)

回答くれました。
~~~
このコードは、Athenaから返されたレスポンスをPandasのデータフレームに変換しています。ただし、Athenaから返されたレスポンスは、JSON形式で表されています。そのため、データフレームに変換する前に、JSON形式から必要なデータを抽出する必要があります。

以下は、Athenaから返されたJSON形式のレスポンスをPandasのデータフレームに変換するためのコード例です。

```python
import json

# query_resultsはAthenaから返されたレスポンス
json_result = json.dumps(query_results)
json_data = json.loads(json_result)

# データフレームに変換
rows = []
for row in json_data['ResultSet']['Rows']:
    r = []
    for v in row['Data']:
        r.append(list(v.values())[0])
    rows.append(r)

df = pd.DataFrame(rows[1:], columns=rows[0])
```

この例では、JSON形式のレスポンスをPythonの辞書型に変換し、必要なデータを抽出しています。その後、Pandasのデータフレームに変換しています。

このコードを使用することで、データが崩れる問題が解決されるはずです。
~~~

これを適用したら

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2989873/31694ee9-7737-4b11-1c49-d4ac42bb4337.png)
無事できました～。

# 最後に
Python初心者でAWSのサービスを外から叩くことも初だったのですが先生のおかげでここまで行けました。
次回は手動で操作していたPython部分をアプリ化してWEBから叩いてみます。