[aiohttp] API ๋ฐ๋ณต๋๋ ๊ตฌ๋ฌธ์ ๋น๋๊ธฐ ํธ์ถ๋ก ์๊ฐ ๋จ์ถํ๊ธฐ
RIOT API ํ๋ก์ ํธ๋ฅผ ํ๋ค๊ฐ aiohttp ๋น๋๊ธฐ ์์ฒญ์ ๋ํด ์๊ฒ ๋๋ค.
์ฒ์ ๋ณด๋ ํจ์์ฌ์ ์ ๋ฆฌ๋ฅผ ํ๊ณ ์ ๊ธ์ ์์ฑํ๊ฒ ๋๋ค.
๋ชฉ์ฐจ
โ ๋ชฉ์ : matchID ๋ฆฌ์คํธ๋ฅผ ํ์ฉํด์ url 205*20=4100 ๊ฐ์ get ์์ฒญ์ ํ์
โ ํด๊ฒฐ๋ฐฉ์ 1 : for loop
โ ํด๊ฒฐ๋ฐฉ์ 2: aiohttp
โ async, await,์ฝ๋ฃจํด ๋?
ํด๊ฒฐ๋ฐฉ์ 1 : for loop
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์ ๊ฑธ๋ฆฌ์ง ์๋๋ก
for ๋ฌธ์ ๋๋ฉฐ ํ๋์ฉ GET ์์ฒญ์ ๋ณด๋ด๋๊ฑด ๊ฐ์ฅ ์ฝ๊ฒ ์๊ฐํ ์๋ ๋ฐฉ๋ฒ์ด๋ค.
ํ์ง๋ง ํ ๋ฒ์ ํ URL ๋ฐ์ ์ฒ๋ฆฌํ ์ ์๊ธฐ ๋๋ฌธ์ ๋ฌด์ฒ ๋นํจ์จ์ ์ด๋ค.
๊ทธ๋์ ๋ฌด๋ ค 40๋ถ์ด ๋๋ ์๊ฐ ๋์ ์ฝ๋๊ฐ ์คํ ๋์์๋ ์ค๋ฅ๊ฐ ๋ฌ๋ค.
ํด๊ฒฐ๋ฐฉ์ 2 : AIOHTTP
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์ด๋ง์ ์คํ๋์๊ณ API๋ ์ ๋๋ก ํธ์ถ๋์๋ค.
์ฑ๋ฅ ์ฉ๋ค.. ์ฝ๋์ ๋ํ ํด์๋ ๋ฌ์ ๋์๋ค.
async, await, coroutine ์ด๋?
async def : ์ฝ๋ฃจํด์ ์ ์ํ๊ธฐ ์ํ ํค์๋
coroutine : ์ง์ ์ ์ด ์ฌ๋ฌ๊ฐ์ธ ํจ์, ๋ณดํต ์ฐ๋ฆฌ๊ฐ ์์ฑํ๋ ํจ์๋ ์ฒ์ ํธ์ถ๋ ์์ ์ด ์ ์ผํ ์ง์ ์ ์
asyncio.wait : ์ด task๋ค์ list์ธ tasks๊ฐ ์ ๋ถ ๋๋ ๋๊น์ง ๊ธฐ๋ค๋ฆฐ๋ค.