이전에 FC Online API를 활용해 스크래핑하고 S3 버킷에 저장하는 Python 코드를 작성하였다. 이번에는 S3-Snowflake-Preset 인프라를 구성할 것이다.
S3 - Snowflake - Preset 연결
S3 버킷은 이전에 구성하였고, Snowflake는 이전에 강의에서 사용했던 것을 그대로 사용하려고 한다. Snowflake는 일정 기간 동안 무료로 사용이 가능한데 아직 10일이 남아서 프로젝트를 진행할 수 있을 것이다. 그리고 Preset도 Workspace를 하나 생성해 주었다.
S3 - Snowflake 연결
IAM 사용자 생성
AWS의 IAM 서비스를 통해 외부 서비스(와 연결이 가능하도록 사용자를 생성한다. 이때 액세스 키와 비밀 액세스 키를 Snowflake의 COPY 명령어와 함께 사용한다. 여기에는 AmazonS3ReadOnlyAccess 정책을 사용하여 권한을 부여하였다.
Snowflake COPY 예시
COPY INTO fc_online.raw_data.defence (matchId, blockTry, blockSuccess, tackleTry, tackleSuccess)
FROM 's3://~/defence.csv'
credentials=(AWS_KEY_ID='-' AWS_SECRET_KEY='-')
FILE_FORMAT = (type='CSV' skip_header=1);
Snowflake - Preset 연결
Preset - Connect Data
Preset의 Connect a database를 통해 Snowflake와 Preset을 연결한다.
API 호출 및 스크래핑 코드 수정
Snowflake에 연결하고 COPY 하는 과정에서 컬럼 순서가 다른 것을 확인하여 이를 수정하였다. initialize_csv_file_in_s3의 cols만 API 호출 시 가져오는 정보의 순서에 맞게 변경해 주었다.
import boto3
import pandas as pd
import requests
from botocore.exceptions import ClientError
import json
class FCOnlineMatch:
def __init__(self):
self.s3 = boto3.client('s3', aws_access_key_id='#', aws_secret_access_key='#', region_name='#')
self.bucket_name = 'fc-online-match'
self.file_key = ['match_detail.csv', 'shoot.csv', 'pass.csv', 'defence.csv']
self.headers = {"x-nxopen-api-key": "#"}
self.initialize_csv_file_in_s3()
def initialize_csv_file_in_s3(self):
cols = [['matchId', 'seasonId', 'matchResult', 'matchEndType', 'systemPause', 'foul', 'injury',
'redCards', 'yellowCards', 'dribble', 'cornerKick', 'possession', 'offsideCount', 'averageRating', 'controller'],
['matchId', 'shootTotal', 'effectiveShootTotal', 'shootOutScore', 'goalTotal', 'goalTotalDisplay','ownGoal','shootHeading',
'goalHeading', 'shootFreekick', 'goalFreekick', 'shootInPenalty', 'goalInPenalty', 'shootOutPenalty', 'goalOutPenalty', 'shootPenaltyKick', 'goalPenaltykick'],
['matchId', 'passTry', 'passSuccess', 'shortPassTry', 'shortPassSuccess', 'longPassTry', 'longPassSuccess','bouncingLobPassTry',
'bouncingLobPassSuccess', 'drivenGroundPassTry', 'drivenGroundPassSuccess', 'throughPassTry', 'throughPassSuccess', 'lobbedThroughPassTry', 'lobbedThroughPassSuccess'],
['matchId', 'blockTry', 'blockSuccess', 'tackleTry', 'tackleSuccess']]
for k, col in zip(self.file_key, cols):
try:
self.s3.head_object(Bucket=self.bucket_name, Key=k)
except ClientError as e:
if e.response['Error']['Code'] == '404':
print(f"File {k} does not exist in bucket {self.bucket_name}. Uploading the file.")
try:
# 파일 업로드
csv_buffer = pd.DataFrame(columns=col).to_csv(index=False)
self.s3.put_object(Bucket=self.bucket_name, Key=k, Body=csv_buffer)
print(f"File {k} has been uploaded to bucket {self.bucket_name}.")
except ClientError as upload_error:
print(f"An error occurred while uploading the file: {upload_error}")
else:
print(f"An error occurred: {e}")
def get_match_id(self):
url = "https://open.api.nexon.com/fconline/v1/match?matchtype=50&offset=0&limit=100&orderby=desc"
response = requests.get(url, headers = self.headers)
return response.json()
def get_csv_files_in_s3(self):
match_detail = pd.read_csv(self.s3.get_object(Bucket=self.bucket_name, Key='match_detail.csv')['Body'])
shoot = pd.read_csv(self.s3.get_object(Bucket=self.bucket_name, Key='shoot.csv')['Body'])
pass_ = pd.read_csv(self.s3.get_object(Bucket=self.bucket_name, Key='pass.csv')['Body'])
defence = pd.read_csv(self.s3.get_object(Bucket=self.bucket_name, Key='defence.csv')['Body'])
return match_detail, shoot, pass_, defence
def append_match_data_to_csv(self, match_detail, shoot, pass_, defence):
match_id = self.get_match_id()
for id in match_id:
url = f'https://open.api.nexon.com/fconline/v1/match-detail?matchid={id}'
response = requests.get(url, headers=self.headers)
if 'matchInfo' in json.loads(response.text):
for match_info in json.loads(response.text)['matchInfo']:
match_info['matchDetail']['matchId'] = id
match_info['shoot']['matchId'] = id
match_info['pass']['matchId'] = id
match_info['defence']['matchId'] = id
match_detail = match_detail._append(match_info['matchDetail'], ignore_index=True)
shoot = shoot._append(match_info['shoot'], ignore_index=True)
pass_ = pass_._append(match_info['pass'], ignore_index=True)
defence = defence._append(match_info['defence'], ignore_index=True)
match_detail['matchResult'] = match_detail['matchResult'].replace({'패': 'lose', '승': 'win', '무': 'draw'})
return match_detail, shoot, pass_, defence
def save_csv_to_s3(self, match_detail, shoot, pass_, defence):
try:
# 파일 업로드
csv_buffer = match_detail.to_csv(index=False)
self.s3.put_object(Bucket=self.bucket_name, Key='match_detail.csv', Body=csv_buffer)
csv_buffer = shoot.to_csv(index=False)
self.s3.put_object(Bucket=self.bucket_name, Key='shoot.csv', Body=csv_buffer)
csv_buffer = pass_.to_csv(index=False)
self.s3.put_object(Bucket=self.bucket_name, Key='pass.csv', Body=csv_buffer)
csv_buffer = defence.to_csv(index=False)
self.s3.put_object(Bucket=self.bucket_name, Key='defence.csv', Body=csv_buffer)
except ClientError as upload_error:
print(f"An error occurred while uploading the file: {upload_error}")
if __name__=='__main__':
test = FCOnlineMatch()
match_detail, shoot, pass_, defence = test.get_csv_files_in_s3()
match_detail, shoot, pass_, defence = test.append_match_data_to_csv(match_detail, shoot, pass_, defence)
test.save_csv_to_s3(match_detail, shoot, pass_, defence)
다음에는 Snowflake Worksheets를 사용해 기본적인 틀을 만들고 COPY 명령으로 S3의 데이터를 가져오도록 할 것이다.
'프로젝트 단위 공부 > [개인 프로젝트] FC Online 공식 경기 분석' 카테고리의 다른 글
[개인 프로젝트] FC Online 공식 경기 분석 (6) - EC2 / crontab 자동화 1 (0) | 2024.06.01 |
---|---|
[개인 프로젝트] FC Online 공식 경기 분석 (5) - Snowflake analytics 테이블 생성 (0) | 2024.05.30 |
[개인 프로젝트] FC Online 공식 경기 분석 (4) - Snowflake 기본 설정 및 COPY (0) | 2024.05.29 |
[개인 프로젝트] FC Online 공식 경기 분석 (2) - S3 버킷 생성 및 스크래핑 코드 작성 (0) | 2024.05.28 |
[개인 프로젝트] FC Online 공식 경기 분석 (1) - 계획서 (0) | 2024.05.25 |