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

๐ŸŽฎRIOT API ๋ถ„์„ ํ”„๋กœ์ ํŠธ(4) - matchID, game data ์ถ”์ถœ

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

MATCH-V4 API์—์„œ matchID ์ถ”์ถœํ•˜๊ธฐ

์ง€๋‚œ ๊ฒŒ์‹œ๊ธ€์—์„œ puuID๊นŒ์ง€ ์ถ”์ถœํ•˜์—ฌ ๋ฐ์ดํ„ฐ ํ”„๋ ˆ์ž„ ํ˜•ํƒœ๋กœ ๋งŒ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค.

/lol/match/v5/matches/by-puuid/{puuid}/ids๋ฅผ ํ™œ์šฉํ•˜์—ฌ matchID๋ฅผ ์ถ”์ถœ ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

 

api_key = MY_API
header = {
    "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"
}

summoner_matchID_list=[]

for puuid in puuid_list:
    url=f"https://asia.api.riotgames.com/lol/match/v5/matches/by-puuid/{puuid}/ids?start=0&count=20&api_key=MY_API"
    rp2=requests.get(url,headers=header)

    if rp2.status_code==429:
        print("Rate limit exceeded. Sleeping for 60 seconds")
        time.sleep(60)
        rp2=requests.get(url,headers=header)
    if rp2.status_code==200:
        summoner_match_data=rp2.json()
        summoner_matchID_list.append({'puuid': puuid, 'match_ids': summoner_match_data})

    # ๋”œ๋ ˆ์ด ์ถ”๊ฐ€
    time.sleep(1)  # ๊ฐ ์š”์ฒญ ์‚ฌ์ด์— 1์ดˆ์˜ ๋”œ๋ ˆ์ด๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ Riot API์˜ Rate Limit์— ๊ฑธ๋ฆฌ์ง€ ์•Š๋„๋ก

 

์ด์ „ ๊ฒŒ์‹œ๊ธ€์—์„œ ๋งŒ๋“  puuID ๋ฆฌ์ŠคํŠธ๋ฅผ ๋„ฃ์–ด์„œ matchID๋ฅผ ํ˜ธ์ถœ ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

 

์ œ๋Œ€๋กœ ํ˜ธ์ถœ๋จ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด์ œ matchID๋ฅผ ๋„ฃ์–ด์„œ ๊ฒŒ์ž„ ์ •๋ณด๋ฅผ ํ˜ธ์ถœํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

 

 

matchID๋ฅผ ํ™œ์šฉํ•ด ๊ฒŒ์ž„ ๋ฐ์ดํ„ฐ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ (๋™๊ธฐ์  ๋ฐฉ์‹)

api_key = MY_API
header = {
    "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
}

match_user_data=[]

for player in summoner_matchID_list:
    puuid=player['puuid']
    match_ids=player['match_ids']
    for match_id in match_ids:
        url = f"https://asia.api.riotgames.com/lol/match/v5/matches/{match_id}"
        rp3=requests.get(url,headers=header)

        if rp3.status_code==429:
            print("Rate limit exceeded. Sleeping for 60 seconds")
            time.sleep(60)
            rp3=requests.get(url,headers=header)
        if rp3.status_code==200:
            match_data=rp3.json()
            match_user_data.append({'puuid': puuid, 'match_id': match_id, 'match_data':match_data})

    # ๋”œ๋ ˆ์ด ์ถ”๊ฐ€
    time.sleep(1)  # ๊ฐ ์š”์ฒญ ์‚ฌ์ด์— 1์ดˆ์˜ ๋”œ๋ ˆ์ด๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ Riot API์˜ Rate Limit์— ๊ฑธ๋ฆฌ์ง€ ์•Š๋„๋ก

 

ํ•ด๋‹น ์ฝ”๋“œ๋ฅผ ๋Œ๋ ธ๋Š”๋ฐ 40๋ถ„ ๋™์•ˆ ๋Œ์•„๊ฐ€๋”๋‹ˆ ๊ฒฐ๊ตญ ์˜ค๋ฅ˜๊ฐ€ ๋‚ฌ์Šต๋‹ˆ๋‹ค.

 

 

API ํ˜ธ์ถœ์„ ๋„ˆ๋ฌด ๋งŽ์ด ํ•ด์„œ ์ƒ๊ธด ์˜ค๋ฅ˜ ๊ฐ™์Šต๋‹ˆ๋‹ค.

250๊ฐœ ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ์•ž์œผ๋กœ ํ‹ฐ์–ด๋ณ„๋กœ 500๊ฐœ์”ฉ์€ ํ˜ธ์ถœํ•ด์•ผ ํ• ํ…๋ฐ, 250*20=4100 ํŒ ์ •๋ณด ํ˜ธ์ถœํ•˜๋Š”๋ฐ ๋„ˆ๋ฌด ์˜ค๋ž˜๊ฑธ๋ฆฌ๊ณ  ์˜ค๋ฅ˜๊ฐ€ ๋–ด์Šต๋‹ˆ๋‹ค. ์ž‘์„ฑํ•œ ์ฝ”๋“œ๊ฐ€ ๋™๊ธฐ์  ๋ฐฉ์‹์œผ๋กœ ์ฝ”๋“œ๋ฅผ ์š”์ฒญํ–ˆ๋Š”๋ฐ ๋™๊ธฐ์  ๋ฐฉ์‹์œผ๋กœ ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•˜๋ฉด ํ•˜๋‚˜์˜ ์š”์ฒญ์ด ์™„๋ฃŒ๋  ๋•Œ๊นŒ์ง€ ๋‹ค์Œ ์š”์ฒญ์„ ๊ธฐ๋‹ค๋ ค์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์‹œ๊ฐ„์ด ์˜ค๋ž˜ ๊ฑธ๋ฆฝ๋‹ˆ๋‹ค.

 

์ด๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ๋น„๋™๊ธฐ ์š”์ฒญ(asynchronous requests)์„ ์‚ฌ์šฉํ•˜๋ฉด ์—ฌ๋Ÿฌ ์š”์ฒญ์„ ๋™์‹œ์— ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์–ด ์†๋„๋ฅผ ํฌ๊ฒŒ ํ–ฅ์ƒ์‹œํ‚ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. aiohttp์™€ ๊ฐ™์€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋น„๋™๊ธฐ์ ์œผ๋กœ API ์š”์ฒญ์„ ๋ณด๋‚ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

 

matchID๋ฅผ ํ™œ์šฉํ•ด ๊ฒŒ์ž„ ๋ฐ์ดํ„ฐ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ (๋น„๋™๊ธฐ์  ๋ฐฉ์‹)

import aiohttp # asyncio๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ HTTP ์š”์ฒญ์„ ํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ
import asyncio # Python 3.3๋ถ€ํ„ฐ ์†Œ๊ฐœ๋œ ๋น„๋™๊ธฐ ์ง€์› ๋ชจ๋“ˆ
import time

# ๋น„๋™๊ธฐ ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•œ ํ•จ์ˆ˜
async def fetch_match_data(session, puuid, match_id, header): 
    # Riot API์—์„œ ๊ฐ match_id์— ๋Œ€ํ•ด ๋น„๋™๊ธฐ์ ์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ์—ญํ• 
    # session : aiohttp.ClientSession()์„ ์‚ฌ์šฉํ•˜์—ฌ ์ƒ์„ฑ๋œ HTTP ์„ธ์…˜ ๊ฐ์ฒด. ๋น„๋™๊ธฐ์ ์œผ๋กœ HTTP ์š”์ฒญ์„ ๋ณด๋‚ด๊ธฐ ์œ„ํ•ด ํ•„์š”
    url = f"https://asia.api.riotgames.com/lol/match/v5/matches/{match_id}" 
    async with session.get(url, headers=header) as response:
        # session์„ ํ†ตํ•ด ์—ฌ๋Ÿฌ๊ฐœ์˜ matchID๋ฅผ ๋™์‹œ์— ์ž…๋ ฅํ•˜์—ฌ url ์ฃผ์†Œ ๊ฐ€์ ธ์˜ค๊ธฐ
        if response.status == 429:
            # Rate limit์— ๊ฑธ๋ฆฌ๋ฉด (status == 429), Retry-After ํ—ค๋” ๊ฐ’์„ ํ™•์ธํ•˜์—ฌ 60์ดˆ ๋งŒํผ ๋Œ€๊ธฐํ•œ ํ›„ ์žฌ์‹œ๋„
            retry_after = int(response.headers.get('Retry-After', 60))  # Retry-After ํ—ค๋” ํ™•์ธ
            print(f"Rate limit exceeded. Sleeping for {retry_after} seconds.")
            await asyncio.sleep(retry_after)  # ๋น„๋™๊ธฐ ๋Œ€๊ธฐ
            # 60์ดˆ๋งŒํผ ๋Œ€๊ธฐ์ค‘์ธ ์ƒํƒœ
            async with session.get(url, headers=header) as retry_response:
                if retry_response.status == 200:
                    # 60์ดˆ๋งŒํผ ๋Œ€๊ธฐ ํ›„ ์žฌ์‹œ๋„
                    return await retry_response.json(), puuid, match_id
        elif response.status == 200:
            return await response.json(), puuid, match_id
            # ์‘๋‹ต์ด ์„ฑ๊ณต์ ์ผ ๊ฒฝ์šฐ (status == 200), ์‘๋‹ต ๋ฐ์ดํ„ฐ๋ฅผ json ํ˜•์‹์œผ๋กœ ๋ฐ˜ํ™˜
        else:
            print(f"Error: {response.status}")
            return None, puuid, match_id
            # ์˜ค๋ฅ˜ ์‘๋‹ต์ด ๋ฐœ์ƒํ•  ๊ฒฝ์šฐ ์ƒํƒœ ์ฝ”๋“œ์™€ ํ•จ๊ป˜ ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€๋ฅผ ์ถœ๋ ฅํ•˜๊ณ  None์„ ๋ฐ˜ํ™˜

# ๋น„๋™๊ธฐ ๋ฉ”์ธ ํ•จ์ˆ˜
async def fetch_all_matches(summoner_matchID_list, header):#์—ฌ๋Ÿฌ ํ”Œ๋ ˆ์ด์–ด์˜ ์—ฌ๋Ÿฌ match_id์— ๋Œ€ํ•ด ๋น„๋™๊ธฐ์ ์œผ๋กœ API ์š”์ฒญ์„ ๋™์‹œ์— ์ฒ˜๋ฆฌ
    match_user_data = []
    async with aiohttp.ClientSession() as session:
        tasks = []
        # ๊ฐ ํ”Œ๋ ˆ์ด์–ด์˜ puuid์™€ ํ•ด๋‹น match_ids์— ๋Œ€ํ•ด fetch_all_data ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ์ž‘์—…(task)์„ ์ƒ์„ฑ
        for player in summoner_matchID_list:
            puuid = player['puuid']
            match_ids = player['match_ids']
            for match_id in match_ids:
                task = asyncio.create_task(fetch_match_data(session, puuid, match_id, header)) 
                # asyncio.create_task()๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋น„๋™๊ธฐ ์ž‘์—…์„ ์ƒ์„ฑํ•˜๊ณ , ์ด ์ž‘์—…์„ ๋ชจ๋‘ ๋ชจ์•„์„œ asyncio.gather()๋กœ ๋™์‹œ์— ์‹คํ–‰
                tasks.append(task)
                await asyncio.sleep(1)  # ๋น„๋™๊ธฐ ๋Œ€๊ธฐ (1์ดˆ)
        responses = await asyncio.gather(*tasks)
        
        # ์‘๋‹ต ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ
        for match_data, puuid, match_id in responses:
            if match_data:
                match_user_data.append({'puuid': puuid, 'match_id': match_id, 'match_data': match_data})

    return match_user_data

 

 

 

2์ดˆ๋งŒ์— ๋๋‚ฌ์Šต๋‹ˆ๋‹ค. ์ฝ”๋“œ์— ๋Œ€ํ•œ ํ•ด์„ค๋„ ๊ฐ™์ด ๋‹ฌ์•„๋†“์•˜์Šต๋‹ˆ๋‹ค.

์ œ๋Œ€๋กœ ํ˜ธ์ถœ๋๋Š”์ง€ ํ™•์ธํ•ด๋ด…์‹œ๋‹ค.

 

sample3=pd.DataFrame(match_user_data)
sample3['match_data'][0]

 

ํ•„์š”ํ•œ ์ •๋ณด๋“ค์„ ๋งž๊ฒŒ ๋ถˆ๋Ÿฌ์™”์Šต๋‹ˆ๋‹ค. 

์ด์ œ ์ด ์ •๋ณด์—์„œ ์‚ฌ์šฉํ•  ๊ฒƒ๋งŒ์„ ์ถ”์ถœํ•˜์—ฌ MySQL DB์— ๋‹ด๊ฒ ์Šต๋‹ˆ๋‹ค.

ํ•˜์ง€๋งŒ ์ด์ „์— ์ž‘์„ฑํ•œ ์ฝ”๋“œ๋“ค๋„ ๋น„๋™๊ธฐ ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋น ๋ฅด๊ฒŒ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ๋„๋ก ์ˆ˜์ • ๊ณผ์ •์„ ๋จผ์ € ๊ฑฐ์น˜๊ฒ ์Šต๋‹ˆ๋‹ค.