๐Ÿ“ฆ๋ถ„์„ ํ”„๋กœ์ ํŠธ/๐ŸŽฎ RIOT API ๋ถ„์„ ๋ฐ ์›น์„œ๋น„์Šค ๊ฐœ๋ฐœ

๐ŸŽฎRIOT API ๋ถ„์„ ํ”„๋กœ์ ํŠธ(6) - ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๊ตฌ์ถ•

๋ฐ์ดํ„ฐํŒ์Šค 2024. 9. 21. 23:22

puuid, matchid sql DB์— ์ €์žฅํ•˜๊ธฐ

 

ํ•œ๋™์•ˆ ๊ธ€์ด ๋œธํ–ˆ๋˜ ์ด์œ ๋Š” ์ถ”์„ ์—ฐํœด๋‚ด๋‚ด DB๋ฅผ ๊ตฌ์ถ•ํ–ˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

riot api rate limit ๋•Œ๋ฌธ์— 1์‹œ๊ฐ„์— 2์ฒœ๊ฐœ ๋ฐ์ดํ„ฐ ์ถ”์ถœ์ด ์ตœ๋Œ€์ž…๋‹ˆ๋‹ค...

import mysql.connector

# MySQL ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์—ฐ๊ฒฐ
connection = mysql.connector.connect(
    host="localhost",        # MySQL ์„œ๋ฒ„ ์ฃผ์†Œ
    user="root",    # MySQL ์‚ฌ์šฉ์ž๋ช…
    password="0224", # MySQL ๋น„๋ฐ€๋ฒˆํ˜ธ
    database="riot_game_database"  # ์‚ฌ์šฉํ•  ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ด๋ฆ„
)

# ์ปค์„œ ์ƒ์„ฑ
cursor = connection.cursor()

# puuid์™€ match_id ๋ฐ์ดํ„ฐ๋ฅผ ํ…Œ์ด๋ธ”์— ์‚ฝ์ž…ํ•˜๋Š” ํ•จ์ˆ˜
def insert_match_id(puuid, match_id):
    sql = """
    INSERT INTO summoner_puuid (puuid, match_id)
    VALUES (%s, %s)
    """
    cursor.execute(sql, (puuid, match_id))


# puuid์™€ ๊ฐ๊ฐ์˜ match_id๋ฅผ ํ…Œ์ด๋ธ”์— ์‚ฝ์ž…
for entry in summoner_matchID_list:
    puuid = entry['puuid']
    match_ids = entry['match_ids']
    
    for match_id in match_ids:
        insert_match_id(puuid, match_id)

# ๋ณ€๊ฒฝ์‚ฌํ•ญ ์ปค๋ฐ‹
connection.commit()

# ์ปค์„œ์™€ ์—ฐ๊ฒฐ ์ข…๋ฃŒ
cursor.close()
connection.close()

 

์ผ๋‹จ puuid์™€ match_id๋ฅผ DB์— ๋‹ด์•˜์Šต๋‹ˆ๋‹ค.

 

 

 

SQL ์„œ๋ฒ„ ์—ฐ๊ฒฐ ๋ฐ ๋ฐ์ดํ„ฐ ๋ถ„ํ• 

ex1_match_ids=match_ids[:2000]
ex2_match_ids=match_ids[2001:4001]
ex3_match_ids=match_ids[4002:6002]
ex4_match_ids=match_ids[6003:8003]
ex5_match_ids=match_ids[8004:10004]
ex6_match_ids=match_ids[10005:10250]

import mysql.connector

# MySQL ์„œ๋ฒ„์— ์—ฐ๊ฒฐ
connection = mysql.connector.connect(
    host="localhost",         # MySQL ์„œ๋ฒ„ ํ˜ธ์ŠคํŠธ ์ด๋ฆ„ (๋ณดํ†ต ๋กœ์ปฌ์ผ ๊ฒฝ์šฐ localhost)
    user="root",      # MySQL ์‚ฌ์šฉ์ž ์ด๋ฆ„
    password="0224",  # MySQL ์‚ฌ์šฉ์ž ๋น„๋ฐ€๋ฒˆํ˜ธ
    database="riot_game_database"    # ์‚ฌ์šฉํ•  ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ด๋ฆ„
)

# ์—ฐ๊ฒฐ์ด ์„ฑ๊ณตํ–ˆ๋Š”์ง€ ํ™•์ธ
if connection.is_connected():
    print("MySQL ์—ฐ๊ฒฐ ์„ฑ๊ณต")
else:
    print("MySQL ์—ฐ๊ฒฐ ์‹คํŒจ")

 

ํ•œ๋ฒˆ์— 10250๊ฐœ(250๋ช… x 10ํŒ์˜๋ฐ์ดํ„ฐ)  ๋ฅผ ๊ฐ€์ ธ์˜ค๋ฉด ์˜ค๋ฅ˜๊ฐ€ ๋‚  ๊ฒƒ ๊ฐ™์•„์„œ 2000๊ฐœ์”ฉ ๋Š์–ด์„œ ๊ฐ€์ ธ์™”์Šต๋‹ˆ๋‹ค.

 

 

 

MATCHID๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ์›ํ•˜๋Š” ์ •๋ณด๋งŒ SQL DB์— ์ €์žฅํ•˜๊ธฐ

import aiohttp
import asyncio
from asyncio_throttle import Throttler

# ๋น„๋™๊ธฐ์ ์œผ๋กœ match ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ํ•จ์ˆ˜
async def fetch_match_data(session, match_id, api_key, throttler):
    url = f"https://asia.api.riotgames.com/lol/match/v5/matches/{match_id}"
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36 Edg/128.0.0.0",
        "Accept-Language": "ko,en;q=0.9,en-US;q=0.8",
        "Accept-Charset": "application/x-www-form-urlencoded; charset=UTF-8",
        "Origin": "https://developer.riotgames.com",
        "X-Riot-Token": api_key
    }
    
    async with throttler:  # ์š”์ฒญ ์†๋„ ์ œํ•œ
        async with session.get(url, headers=headers) as response:
            if response.status == 429:  # Rate limit ์ฒ˜๋ฆฌ
                retry_after = int(response.headers.get('Retry-After', 60))  # Retry-After ํ—ค๋” ํ™•์ธ
                print(f"Rate limit exceeded for match {match_id}. Sleeping for {retry_after} seconds.")
                await asyncio.sleep(retry_after)  # ๋น„๋™๊ธฐ ๋Œ€๊ธฐ
                return await fetch_match_data(session, match_id, api_key, throttler)  # ๋‹ค์‹œ ์‹œ๋„
            elif response.status == 200:
                match_data = await response.json()  # JSON ๋ฐ์ดํ„ฐ ๋ฐ˜ํ™˜
                queue_id = match_data.get('info', {}).get('queueId', None)
                if queue_id == 420:  # Solo Rank ๋ชจ๋“œ (Queue ID 420)๋งŒ ๊ฐ€์ ธ์˜ด
                    return match_data
                else:
                    print(f"Skipping match {match_id} because queueId is not 420")
                    return None
            else:
                print(f"Error: {response.status} for match ID {match_id}")
                return None


async def fetch_all_matches(ex5_match_ids, api_key):
    throttler = Throttler(rate_limit=20, period=1)  # ์ดˆ๋‹น 20๊ฐœ์˜ ์š”์ฒญ์œผ๋กœ ์ œํ•œ
    async with aiohttp.ClientSession() as session:
        tasks = [fetch_match_data(session, match_id, api_key, throttler) for match_id in ex5_match_ids]
        responses = await asyncio.gather(*tasks)
        for response in responses:
            if response is None:
                print("Failed to fetch data for a match.")
        return [response for response in responses if response is not None]
    
# MYSQL ์—ฐ๊ฒฐ ์„ค์ •
def create_db_connection():
    connection = mysql.connector.connect(
    host="localhost",         # MySQL ์„œ๋ฒ„ ํ˜ธ์ŠคํŠธ ์ด๋ฆ„ (๋ณดํ†ต ๋กœ์ปฌ์ผ ๊ฒฝ์šฐ localhost)
    user="root",      # MySQL ์‚ฌ์šฉ์ž ์ด๋ฆ„
    password="0224",  # MySQL ์‚ฌ์šฉ์ž ๋น„๋ฐ€๋ฒˆํ˜ธ
    database="riot_game_database"    # ์‚ฌ์šฉํ•  ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ด๋ฆ„
)
    return connection

# MYSQL ์— ๋งค์น˜ ๋ฐ์ดํ„ฐ๋ฅผ ์‚ฝ์ž…
def insert_match_data(connection,match_data):
    cursor=connection.cursor()
    for match in match_data:
        match_id = match.get('metadata', {}).get('matchId', 'Unknown Match ID')
        
        inser_query = """
        INSERT INTO matches5 (match_id, summoner_name, puuid, kills, deaths, gold_earned, wards_placed, wards_bought, css, assists, kda, teamPosition)
        VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
        """
        for participant in match.get('info', {}).get('participants', []):
            data = ( match.get('metadata', {}).get('matchId', 'Unknown Match ID'),
                participant.get('summonerName'),
                participant.get('puuid'),  # puuid ์ถ”๊ฐ€
                participant.get('kills'),
                participant.get('deaths'),
                participant.get('goldEarned', 0),
                participant.get('wardPlaced', 0),
                participant.get('visionWardsBoughtInGame', 0),
                (participant.get('totalMinionsKilled', 0) + participant.get('neutralMinionsKilled', 0)) / (match.get('info', {}).get('gameDuration', 1) / 60),
                participant.get('assists'),
                participant.get('challenges', {}).get('kda'),
                participant.get('teamPosition')  # teamPosition ์ถ”๊ฐ€
            )
            try:
                cursor.execute(inser_query, data)
            except mysql.connector.Error as err:
                print(f"Error: {err}")
    connection.commit()
    cursor.close()

# ๋น„๋™๊ธฐ ๋ฉ”์ธ ํ•จ์ˆ˜
async def main():
    api_key = "MY_API"  # Riot Games API ํ‚ค

    # ๋ชจ๋“  match_ids์— ๋Œ€ํ•ด ๊ฒŒ์ž„ ์ •๋ณด ๊ฐ€์ ธ์˜ค๊ธฐ
    match_data_list = await fetch_all_matches(ex5_match_ids, api_key)
    
    # mysql ์—ฐ๊ฒฐ ๋ฐ ๋ฐ์ดํ„ฐ ์‚ฝ์ž…
    connection=create_db_connection()
    insert_match_data(connection,match_data_list)
    connection.close()

# asyncio ์‹คํ–‰
await main()

 

๋ฌธ์ œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์ฝ”๋“œ๊ฐ€ ์ž˜ ์‹คํ–‰๋˜๋‹ค๊ฐ€ ์˜ค๋ฅ˜๊ฐ€ ๋‚ฌ์ง€ ๋ญก๋‹ˆ๊นŒ

๋ถ„๋ช… ex1~4๊นŒ์ง„ ์ž˜ ๋๋Š”๋ฐ ex5์—์„œ ์˜ค๋ฅ˜๊ฐ€ ๋‚ฌ์Šต๋‹ˆ๋‹ค.

 

 

css๋ฅผ ๊ณ„์‚ฐํ•˜๋Š” ์‹์ด ์•„๋ž˜์™€ ๊ฐ™์€๋ฐ ๋ถ„๋ชจ์— 0์ด ๋“ค์–ด๊ฐ€๋Š” ๊ฐ’์ด ์žˆ๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค..

(participant.get('totalMinionsKilled', 0) + participant.get('neutralMinionsKilled', 0)) / (match.get('info', {}).get('gameDuration', 1) / 60)

 

๊ฒŒ์ž„์‹œ๊ฐ„์ด 0์ธ ๊ฒฝ์šฐ๊ฐ€ ์žˆ๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. 

API์˜ค๋ฅ˜์ธ์ง€ ๊บผ๋ฒ„๋ฆฐ ๊ฑด์ง€๋Š” ๋ชจ๋ฅด๊ฒ ์ง€๋งŒ ํ•ด๋‹น ์˜ค๋ฅ˜์ผ ๊ฒฝ์šฐ๋„ ๊ณ„์‚ฐํ•ด์ฃผ๋Š” ์ฝ”๋“œ๋กœ ๋‹ค์‹œ์ˆ˜์ •ํ•ฉ๋‹ˆ๋‹ค.

 

import aiohttp
import asyncio
import mysql.connector
from asyncio_throttle import Throttler

# ๋น„๋™๊ธฐ์ ์œผ๋กœ match ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ํ•จ์ˆ˜
async def fetch_match_data(session, match_id, api_key, throttler):
    url = f"https://asia.api.riotgames.com/lol/match/v5/matches/{match_id}"
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36 Edg/128.0.0.0",
        "Accept-Language": "ko,en;q=0.9,en-US;q=0.8",
        "Accept-Charset": "application/x-www-form-urlencoded; charset=UTF-8",
        "Origin": "https://developer.riotgames.com",
        "X-Riot-Token": api_key
    }
    
    async with throttler:  # ์š”์ฒญ ์†๋„ ์ œํ•œ
        async with session.get(url, headers=headers) as response:
            if response.status == 429:  # Rate limit ์ฒ˜๋ฆฌ
                retry_after = int(response.headers.get('Retry-After', 60))  # Retry-After ํ—ค๋” ํ™•์ธ
                print(f"Rate limit exceeded for match {match_id}. Sleeping for {retry_after} seconds.")
                await asyncio.sleep(retry_after)  # ๋น„๋™๊ธฐ ๋Œ€๊ธฐ
                return await fetch_match_data(session, match_id, api_key, throttler)  # ๋‹ค์‹œ ์‹œ๋„
            elif response.status == 200:
                match_data = await response.json()  # JSON ๋ฐ์ดํ„ฐ ๋ฐ˜ํ™˜
                queue_id = match_data.get('info', {}).get('queueId', None)
                if queue_id == 420:  # Solo Rank ๋ชจ๋“œ (Queue ID 420)๋งŒ ๊ฐ€์ ธ์˜ด
                    return match_data
                else:
                    print(f"Skipping match {match_id} because queueId is not 420")
                    return None
            else:
                print(f"Error: {response.status} for match ID {match_id}")
                return None

async def fetch_all_matches(ex5_match_ids, api_key):
    throttler = Throttler(rate_limit=20, period=1)  # ์ดˆ๋‹น 20๊ฐœ์˜ ์š”์ฒญ์œผ๋กœ ์ œํ•œ
    async with aiohttp.ClientSession() as session:
        tasks = [fetch_match_data(session, match_id, api_key, throttler) for match_id in ex5_match_ids]
        responses = await asyncio.gather(*tasks)
        return [response for response in responses if response is not None]

# MYSQL ์—ฐ๊ฒฐ ์„ค์ •
def create_db_connection():
    connection = mysql.connector.connect(
        host="localhost",         # MySQL ์„œ๋ฒ„ ํ˜ธ์ŠคํŠธ ์ด๋ฆ„
        user="root",              # MySQL ์‚ฌ์šฉ์ž ์ด๋ฆ„
        password="0224",          # MySQL ์‚ฌ์šฉ์ž ๋น„๋ฐ€๋ฒˆํ˜ธ
        database="riot_game_database"  # ์‚ฌ์šฉํ•  ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ด๋ฆ„
    )
    return connection

# MYSQL์— ๋งค์น˜ ๋ฐ์ดํ„ฐ๋ฅผ ์‚ฝ์ž…
def insert_match_data(connection, match_data):
    cursor = connection.cursor()
    for match in match_data:
        match_id = match.get('metadata', {}).get('matchId', 'Unknown Match ID')
        
        inser_query = """
        INSERT INTO matches5 (match_id, summoner_name, puuid, kills, deaths, gold_earned, wards_placed, wards_bought, css, assists, kda, teamPosition)
        VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
        """
        for participant in match.get('info', {}).get('participants', []):
            total_minions_killed = participant.get('totalMinionsKilled', 0)
            neutral_minions_killed = participant.get('neutralMinionsKilled', 0)
            game_duration = match.get('info', {}).get('gameDuration', 1) / 60  # ๋ถ„ ๋‹จ์œ„๋กœ ๋ณ€ํ™˜
            
            # ๊ฒŒ์ž„ ์‹œ๊ฐ„์ด 0์ผ ๊ฒฝ์šฐ ์ฒ˜๋ฆฌ
            css = (total_minions_killed + neutral_minions_killed) / game_duration if game_duration > 0 else 0
            
            data = (
                match_id,
                participant.get('summonerName'),
                participant.get('puuid'),
                participant.get('kills'),
                participant.get('deaths'),
                participant.get('goldEarned', 0),
                participant.get('wardsPlaced', 0),
                participant.get('visionWardsBoughtInGame', 0),
                css,
                participant.get('assists'),
                participant.get('challenges', {}).get('kda'),
                participant.get('teamPosition')
            )
            try:
                cursor.execute(inser_query, data)
            except mysql.connector.Error as err:
                print(f"Error: {err}")
    connection.commit()
    cursor.close()

# ๋น„๋™๊ธฐ ๋ฉ”์ธ ํ•จ์ˆ˜
async def main():
    api_key = "MY_API"  # Riot Games API ํ‚ค

    match_data_list = await fetch_all_matches(ex5_match_ids, api_key)
    
    # MySQL ์—ฐ๊ฒฐ ๋ฐ ๋ฐ์ดํ„ฐ ์‚ฝ์ž…
    connection = create_db_connection()
    insert_match_data(connection, match_data_list)
    connection.close()

# asyncio ์‹คํ–‰
await main()

 

์ด์ œ ๊ฒŒ์ž„์‹œ๊ฐ„์ด 0์ธ ๊ฒฝ์šฐ๋„ ์ œ๋Œ€๋กœ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

DB์—์„œ ์†”๋กœ๋žญํฌ์— ํ•ด๋‹นํ•˜๋Š” ๊ฒƒ๋งŒ ๋‹ค์‹œ ๊ฐ€์ ธ์™€์„œ 9์ฒœ๊ฐœ๊ฐ€ ์กฐ๊ธˆ ๋„˜๋Š” ๋ฐ์ดํ„ฐ๋งŒ ๋‚จ๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

matchid๋Š” ์•„๋ ˆ๋‚˜ ๋ชจ๋“œ๋„ ํฌํ•จ๋˜์–ด ์žˆ๊ธฐ์— ๊ทธ ๋ถ€๋ถ„์€ ์ œ์™ธํ•˜์˜€์Šต๋‹ˆ๋‹ค.

 

์ด์ œ ์ด DB๋ฅผ ๊ฐ€์ง€๊ณ  ์œ ์ €๋“ค์˜ ํ‰๊ท ์„ ํƒœ๋ธ”๋กœ๋กœ ๊ตฌํ˜„ํ•  ์˜ˆ์ •์ž…๋‹ˆ๋‹ค.