이번에는 FC Online API를 requests 모듈을 사용해 스크래핑하여 S3 버킷에 저장하는 Python 코드를 작성할 것이다. 데이터 저장은 csv 파일에 진행되고, S3에서 파일을 가져와 아래에 덧붙이는 방식이다.
S3 버킷 & IAM 사용자 생성
스크래핑을 진행하여 만들어진 csv 파일을 저장할 S3 버킷을 생성하고, Python에서 연결할 수 있도록 IAM 사용자를 생성할 것이다. S3에 대해 간단히 알고 싶다면 아래의 링크를 참고하면 된다.
S3 버킷 생성
S3 버킷 생성
fc-online-match라는 이름의 S3 버킷을 생성하였다. 이전에 실습할 때는 퍼블릭
퍼블릭 액세스 차단
이전 학습을 진행할 때, 간단하게 S3의 퍼블릭 액세스 차단을 해제한 뒤 접근하였다. 이번에는 퍼블릭 액세스 차단을 설정하고 IAM의 Key로 접근하여 보안을 조금이나마 신경 써보려고 한다.
IAM 사용자 생성
IAM 사용자 생성
Python에서 S3에 접근할 수 있도록 fc-online-s3라는 사용자를 생성하였다. 그리고 액세스 키와 비밀 액세스 키를 발급받아 기록해두었다.
정책 설정
사용자를 생성하고 생성한 버킷에 접근할 수 있는 정책을 설정해야 한다. 아래 정책 fc-online-match 버킷의 모든 디렉터리에 대한 ListBucket, GetObject, PutObject, DeleteObject 권한을 부여한다. 생성된 정책을 사용자에게 연결하여 해당 사용자가 S3에 접근할 수 있도록 하였다.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:ListBucket",
"s3:GetObject",
"s3:PutObject",
"s3:DeleteObject"
],
"Resource": [
"arn:aws:s3:::fc-online-match",
"arn:aws:s3:::fc-online-match/*"
]
}
]
}
API 호출 및 스크래핑
스크래핑 코드 동작 순서
- S3 버킷과 연동
- S3에 csv 파일이 없으면 생성
- S3에서 csv 파일 가져오기
- csv 파일에 API 데이터 추가
- match id 가져오기
- match id에 대한 경기 정보 가져오기
- S3에 csv 파일 저장
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)
메서드
__init__(self)
- S3 버킷 연동 및 사용할 변수 선언, S3에 csv 파일이 없으면 생성
- boto3 라이브러리를 통해 S3 버킷과 연동
- 다른 메서드에서 사용할 bucket_name, file_key, headers 변수 선언
- S3에 csv 파일이 존재하지 않으면 미리 생성
initialize_csv_file_in_s3(self)
- S3에 csv 파일이 존재하지 않으면 미리 생성
- match_detail.csv, shoot.csv, pass.csv, defence.csv
- 각 데이터에 맞는 컬럼을 설정하여 header만 존재하는 csv 파일 생성
get_match_id(self)
- FC Online API를 호출하여 공식 경기(matchtype=50)의 match id를 가져옴
- 이후에 해당 match id에 해당하는 경기 정보를 S3에 적재
append_match_data_to_csv(self, match_detail, shoot, pass_, defence)
- get_match_id를 통해 match id를 가져옴
- 가져온 match id에 대한 경기 정보를 가져와 csv 파일에 append
save_csv_to_s3(self, match_detail, shoot, pass_, defence)
- 데이터 추가가 완료된 csv 파일을 S3에 적재
코드
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', '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', '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)
다음에는 S3 - Snowflake - Preset 인프라를 구성할 것이다.
'프로젝트 단위 공부 > [개인 프로젝트] 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 공식 경기 분석 (3) - 인프라 구성(S3, Snowflake, Preset) (0) | 2024.05.29 |
[개인 프로젝트] FC Online 공식 경기 분석 (1) - 계획서 (0) | 2024.05.25 |