Lina's Toolbox

[Django/RIOT API] 6. 유저네임으로 챔피언정보(선호 챔피언, 챔피언 이미지) 조회하기 (champion-mastery-v4) 본문

스파르타 내일 배움 캠프 AI 웹개발 과정/python

[Django/RIOT API] 6. 유저네임으로 챔피언정보(선호 챔피언, 챔피언 이미지) 조회하기 (champion-mastery-v4)

Woolina 2024. 10. 12. 15:32

 

 

 

puuid로 챔피언 마스터리 정보 불러오기

 

https://developer.riotgames.com/apis#champion-mastery-v4

 

Riot Developer Portal

 

developer.riotgames.com

챔피언 숙련도 관련 정보는 여기서 얻을 수 있다!

나는 puuid를 통해 상위 n개의 선호 챔피언 정보를 가져오는

/lol/champion-mastery/v4/champion-masteries/by-puuid/{encryptedPUUID}/top를 사용했다.

 

리턴 값이 꽤 많은데, 사실 내가 사용할 건 championId 딱 하나다. 😅

 

account-v1를 통해 조회한 인코딩된 puuid를 입력하고,

내가 보고싶은 상위 선호 챔피언의 갯수(count)를 적고 Api key 선택 후 요청하면,

 

Response Body

[
    {
        "puuid": "FGS9t-Uro7Inj8Gksk4NxIvM-dfgdkgjMiPCVKBzo8DbL9mrbp7s_I5-GLjWBC83F5Iu_De6g",
        "championId": 233,
        "championLevel": 11,
        "championPoints": 86999,
        "lastPlayTime": 1727391869000,
        "championPointsSinceLastLevel": 399,
        "championPointsUntilNextLevel": 10601,
        "markRequiredForNextLevel": 2,
        "tokensEarned": 1,
        "championSeasonMilestone": 0,
        "milestoneGrades": [
            "C-"
        ],
        "nextSeasonMilestone": {
            "requireGradeCounts": {
                "B-": 1,
                "C-": 4
            },
            "rewardMarks": 1,
            "bonus": false,
            "rewardConfig": {
                "rewardValue": "5f4333db-e90d-4705-903b-08dbf5e61006",
                "rewardType": "HEXTECH_CHEST",
                "maximumReward": 6
            },
            "totalGamesRequires": 5
        }
    }
]

가장 상위 선호 챔피언에 대한 마스터리 정보가 반환된다!

여기서 내가 사용할 값은 championId

 

파이썬 코드

def get_top_champions(api_key, puuid):
    """유저의 상위 5개 챔피언 ID를 조회합니다."""
    url_top_champions = f"https://kr.api.riotgames.com/lol/champion-mastery/v4/champion-masteries/by-puuid/{puuid}/top?count=5&api_key={api_key}"

    try:
        response = requests.get(url_top_champions, timeout=10)
        response.raise_for_status()  # HTTPError가 발생하면 예외 발생
        return response.json()

    except requests.exceptions.RequestException as e:
        print(f"Error fetching top champions: {e}")
        return []

상위 5개를 조회할 것이므로 아예 endpoint에 ?count=5 가 추가되어있다.


챔피언 Id로 챔피언 이름, 챔피언 이미지 불러오기

 

그런데 여기서 챔피언 ID는 그냥 int값이므로 쓸모가 없다.

나는 이 챔피언 아이디 값을 통해 해당 챔피언의 이름과, 이미지를 얻고싶었다.

이렇게 구현하는게 내 목표

 

Data Dragon이 sdn으로 챔피언에 대한 정보와 이미지를 제공해주는 것을 찾았다.

https://ddragon.leagueoflegends.com/cdn/14.20.1/data/ko_KR/champion.json
https://ddragon.leagueoflegends.com/cdn/14.20.1/img/champion/Sona.png

 

이걸 이용하면 되겠다! 싶었다.

 

참고로 url에서 14.20.1은 게임의 버전으로,

만약 낮은 게임 버전으로 검색했을 경우 당시에 아직 출시되지 않았던 챔피언 정보는 나오지 않는다.

따라서 최신 버전을 적어주는 게 좋다.

 

ddragon sdn에서, id가 챔피언 명이고,

챔피언 이미지 sdn은 url 마지막에 /{챔피언이름}.png 로 들어가므로, 이것을 이용해야겠다고 생각했다.

 

파이썬 코드

def get_champion_name(champion_id):
    """주어진 챔피언 ID로 챔피언 이름을 조회합니다."""
    url_champion_data = "https://ddragon.leagueoflegends.com/cdn/14.20.1/data/ko_KR/champion.json"
    try:
        response = requests.get(url_champion_data, timeout=10)
        response.raise_for_status()
        champions = response.json()["data"]
        
        for champion in champions.values():
            if champion["key"] == str(champion_id):
                return champion["id"], champion["name"]  # (챔피언 ID, 챔피언 이름)

    except requests.exceptions.RequestException as e:
        print(f"Error fetching champion data: {e}")
    return None, None
    
 
 # 상위 5개 챔피언 ID 조회
top_champions = get_top_champions(api_key, puuid)
champion_info = []

for champion in top_champions:
	champion_id = champion['championId']
    champion_name, _ = get_champion_name(champion_id)
        
    if champion_name:  # 챔피언 이름이 유효한 경우
    	champion_image_link = f"https://ddragon.leagueoflegends.com/cdn/14.20.1/img/champion/{champion_name}.png"
        champion_info.append({
        "championId": champion_id,
        "championName": champion_name,
        "championImage": champion_image_link
		})

 


API 호출 파이썬 전체코드

 

profiles/riot.py

"""
description:
라이엇 API 활용해
라이엇 유저네임, 유저태그 입력하면
해당 유저가 존재한다면
프로필 아이콘, 레벨, 최근 수정일, 티어, 랭크, 승패 수, 선호 포지션 등을 반환.

작성자: 김우린
작성일: 2024-10-12
"""
import sys
import os
import requests
from urllib.parse import quote

# 현재 파일의 경로를 기준으로 상위 디렉토리(프로젝트 루트)를 PYTHONPATH에 추가
sys.path.append(os.path.dirname(os.path.abspath(__file__)) + "/..")

from wpgg.settings import RIOT_API_KEY

# API 키 설정
api_key = RIOT_API_KEY

def get_user_puuid(api_key, riot_id, tag_line):
    """주어진 리그 ID와 태그라인으로 유저의 PUUID를 조회합니다."""
    encoded_riot_id = quote(riot_id)
    encoded_tag_line = quote(tag_line)

    url_puuid = f"https://asia.api.riotgames.com/riot/account/v1/accounts/by-riot-id/{encoded_riot_id}/{encoded_tag_line}?api_key={api_key}"

    try:
        response = requests.get(url_puuid, timeout=10)
        if response.status_code == 404:
            return None  # 유저가 존재하지 않음

        response.raise_for_status()  # HTTPError가 발생하면 예외 발생
        return response.json()['puuid']

    except requests.exceptions.RequestException as e:
        print(f"Error fetching PUUID: {e}")
        return None

def get_user_profile(api_key, puuid):
    """PUUID로부터 유저의 프로필 정보를 조회합니다."""
    url_profile = f"https://kr.api.riotgames.com/lol/summoner/v4/summoners/by-puuid/{puuid}?api_key={api_key}"

    try:
        response = requests.get(url_profile, timeout=10)
        response.raise_for_status()  # HTTPError가 발생하면 예외 발생
        return response.json()

    except requests.exceptions.RequestException as e:
        print(f"Error fetching profile: {e}")
        return None

def get_user_league(api_key, summoner_id):
    """소환사 ID로부터 유저의 리그 정보를 조회합니다."""
    url_league = f"https://kr.api.riotgames.com/lol/league/v4/entries/by-summoner/{summoner_id}?api_key={api_key}"

    try:
        response = requests.get(url_league, timeout=10)
        response.raise_for_status()  # HTTPError가 발생하면 예외 발생
        return response.json()

    except requests.exceptions.RequestException as e:
        print(f"Error fetching league info: {e}")
        return None

def get_match_ids(api_key, puuid):
    """PUUID로부터 유저의 매치 ID 목록을 조회합니다."""
    url_match_ids = f"https://asia.api.riotgames.com/lol/match/v5/matches/by-puuid/{puuid}/ids?api_key={api_key}"

    try:
        response = requests.get(url_match_ids, timeout=10)
        response.raise_for_status()  # HTTPError가 발생하면 예외 발생
        return response.json()

    except requests.exceptions.RequestException as e:
        print(f"Error fetching match IDs: {e}")
        return None

def get_match_info(api_key, match_id):
    """매치 ID로부터 매치 정보를 조회합니다."""
    url_match_info = f"https://asia.api.riotgames.com/lol/match/v5/matches/{match_id}?api_key={api_key}"

    try:
        response = requests.get(url_match_info, timeout=10)
        response.raise_for_status()  # HTTPError가 발생하면 예외 발생
        return response.json()

    except requests.exceptions.RequestException as e:
        print(f"Error fetching match info: {e}")
        return None

def get_user_preferred_position(api_key, puuid):
    """PUUID로부터 유저의 선호 포지션을 조회합니다."""
    positions = []
    
    match_ids = get_match_ids(api_key, puuid)
    if not match_ids:
        return "해당 유저의 매치 기록이 없습니다."

    last_match_id = match_ids[0]  # 가장 최근 매치 ID
    match_info = get_match_info(api_key, last_match_id)

    if not match_info:
        return "매치 정보 조회 실패."

    participants = match_info['info']['participants']
    for player in participants:
        if player['puuid'] == puuid:
            positions.append(player['individualPosition'])
            

    # 가장 많이 등장한 포지션 반환 (선호 포지션)
    if positions:
        return max(set(positions), key=positions.count)
    
    return "포지션 정보 없음"

def get_top_champions(api_key, puuid):
    """유저의 상위 5개 챔피언 ID를 조회합니다."""
    url_top_champions = f"https://kr.api.riotgames.com/lol/champion-mastery/v4/champion-masteries/by-puuid/{puuid}/top?count=5&api_key={api_key}"

    try:
        response = requests.get(url_top_champions, timeout=10)
        response.raise_for_status()  # HTTPError가 발생하면 예외 발생
        return response.json()

    except requests.exceptions.RequestException as e:
        print(f"Error fetching top champions: {e}")
        return []

def get_champion_name(champion_id):
    """주어진 챔피언 ID로 챔피언 이름을 조회합니다."""
    url_champion_data = "https://ddragon.leagueoflegends.com/cdn/14.20.1/data/ko_KR/champion.json"
    try:
        response = requests.get(url_champion_data, timeout=10)
        response.raise_for_status()
        champions = response.json()["data"]
        
        for champion in champions.values():
            if champion["key"] == str(champion_id):
                return champion["id"], champion["name"]  # (챔피언 ID, 챔피언 이름)

    except requests.exceptions.RequestException as e:
        print(f"Error fetching champion data: {e}")
    return None, None

def get_user_info(api_key, riot_id, tag_line):
    """유저의 정보를 종합적으로 조회합니다."""
    puuid = get_user_puuid(api_key, riot_id, tag_line)
    if not puuid:
        return {"error": "해당 유저는 존재하지 않습니다."}

    profile_data = get_user_profile(api_key, puuid)
    if not profile_data:
        return {"error": "프로필 정보를 가져오는 데 실패했습니다."}

    summoner_id = profile_data['id']
    league_data = get_user_league(api_key, summoner_id)
    preferred_position = get_user_preferred_position(api_key, puuid)

    # 프로필 아이콘 URL 생성
    profile_icon_link = f"https://raw.communitydragon.org/latest/game/assets/ux/summonericons/profileicon{profile_data['profileIconId']}.png"

    # 상위 5개 챔피언 ID 조회
    top_champions = get_top_champions(api_key, puuid)
    champion_info = []

    for champion in top_champions:
        champion_id = champion['championId']
        champion_name, _ = get_champion_name(champion_id)
        
        if champion_name:  # 챔피언 이름이 유효한 경우
            champion_image_link = f"https://ddragon.leagueoflegends.com/cdn/14.20.1/img/champion/{champion_name}.png"
            champion_info.append({
                "championId": champion_id,
                "championName": champion_name,
                "championImage": champion_image_link
            })

    # 리턴할 정보 구성
    user_info = {
        "profileIconId": profile_data['profileIconId'],
        "profileIconLink": profile_icon_link,
        "summonerLevel": profile_data['summonerLevel'],
        "revisionDate": profile_data['revisionDate'],
        "league": [],
        "preferredPosition": preferred_position,  # 유저의 선호 포지션 추가
        "topChampions": champion_info  # 유저의 상위 챔피언 정보 추가
    }

    # 리그 정보에서 'RANKED_SOLO_5x5' 큐 타입만 필터링하여 추가
    if league_data:
        for entry in league_data:
            if entry['queueType'] == 'RANKED_SOLO_5x5':
                league_info = {
                    "tier": entry['tier'],
                    "rank": entry['rank'],
                    "leaguePoints": entry['leaguePoints'],
                    "wins": entry['wins'],
                    "losses": entry['losses'],
                    "veteran": entry['veteran'],
                    "inactive": entry['inactive'],
                    "freshBlood": entry['freshBlood'],
                    "hotStreak": entry['hotStreak']
                }
                user_info["league"].append(league_info)

    return user_info

# 함수 호출 예시
# riot_id = '미밀면'  # 유저 이름
# tag_line = 'KR1'      # 태그라인

# user_info = get_user_info(api_key, riot_id, tag_line)
# print(user_info)

# 리턴예시
# {'profileIconId': 6631, 'profileIconLink': 'https://raw.communitydragon.org/latest/game/assets/ux/summonericons/profileicon6631.png', 'summonerLevel': 125, 'revisionDate': 1728712811941, 'league': [{'tier': 'GOLD', 'rank': 'III', 'leaguePoints': 3, 'wins': 12, 'losses': 8, 'veteran': False, 'inactive': False, 'freshBlood': False, 'hotStreak': False}], 'preferredPosition': 'JUNGLE', 'topChampions': [{'championId': 233, 'championName': 'Briar', 'championImage': 'https://ddragon.leagueoflegends.com/cdn/14.20.1/img/champion/Briar.png'}, {'championId': 78, 'championName': 'Poppy', 'championImage': 'https://ddragon.leagueoflegends.com/cdn/14.20.1/img/champion/Poppy.png'}, {'championId': 32, 'championName': 'Amumu', 'championImage': 'https://ddragon.leagueoflegends.com/cdn/14.20.1/img/champion/Amumu.png'}, {'championId': 163, 'championName': 'Taliyah', 'championImage': 'https://ddragon.leagueoflegends.com/cdn/14.20.1/img/champion/Taliyah.png'}, {'championId': 14, 'championName': 'Sion', 'championImage': 'https://ddragon.leagueoflegends.com/cdn/14.20.1/img/champion/Sion.png'}]}

내 라이엇 AI 활용 첫번째 포스팅부터 모든 것을 합친 코드이다!


유저네임, 유저태그를 통해 → puuid를 불러오고

 

→ puuid를 통해 프로필 정보(소환사 레벨, 프로필 아이콘, summoner ID)

→ summoner ID를 통해 리그정보(티어, 랭크, 승패 수 등) 조회,

 

→ puuid로 매치정보 조회 → 얻은 매치 Id로 선호 포지션 조회 

 

→ puuid로 챔피언 마스터리 정보 조회

→ 상위 5개 선호 챔피언 조회

→ 챔피언 Id로 ddragon sdn에서 챔피언 이름,이미지 가져오기


장고 전체 코드 (html, urls.py)

profiles/urls.py

from django.urls import path
from . import views

urlpatterns = [ 
    path('riotPage/', views.RiotPageView.as_view(), name='user-index'),
    path('riot/', views.GetRiotInfoView.as_view(), name='user-profile'),
]

 

urls.py

from django.urls import path, include

urlpatterns = [
    path('api/profile/', include('profiles.urls')),
]


profiles/views.py

from wpgg.settings import RIOT_API_KEY

class RiotPageView(generic.TemplateView):
    template_name = 'profiles/riot.html'

class GetRiotInfoView(APIView):
    def get(self, request):
        riot_username = request.query_params.get('riot_id')
        tag_line = request.query_params.get('tag_line')

        if not riot_username or not tag_line:
            return Response({"message": "유효하지 않은 요청입니다."}, status=status.HTTP_400_BAD_REQUEST)

        user_info = get_user_info(RIOT_API_KEY, riot_username, tag_line)

        if 'error' in user_info:
            return Response({"message": "소환사에 대한 정보를 찾을 수 없습니다."}, status=status.HTTP_404_NOT_FOUND)

        return Response(user_info, status=status.HTTP_200_OK)

wpgg는 내 프로젝트 앱 이름이다.

profiles/templates/profiles/riot.html

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Riot 유저 프로필</title>
    <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
</head>
<body>
    <h1>리그 오브 레전드 유저 정보 조회</h1>
    <form id="riotForm" onsubmit="fetchUserInfo(event)">
        <label for="riotId">유저 이름:</label>
        <input type="text" id="riotId" required>
        <br>
        <label for="tagLine">태그라인:</label>
        <input type="text" id="tagLine" required>
        <br>
        <button type="submit">조회</button>
    </form>

    <div id="result" style="margin-top: 20px;"></div>

    <script>
        async function fetchUserInfo(event) {
            event.preventDefault();  // 기본 폼 제출 방지
            const riotId = document.getElementById("riotId").value;
            const tagLine = document.getElementById("tagLine").value;

            try {
                const response = await fetch(`http://127.0.0.1:8000/api/profile/riot/?riot_id=${encodeURIComponent(riotId)}&tag_line=${encodeURIComponent(tagLine)}`, {
                    method: 'GET',  // GET 메서드로 변경
                    headers: {
                        'Content-Type': 'application/json',
                    },
                });

                if (!response.ok) {
                    throw new Error('네트워크 응답이 좋지 않습니다.');
                }

                const data = await response.json();
                displayUserInfo(data);
            } catch (error) {
                document.getElementById("result").innerText = error.message;
            }
        }

        function displayUserInfo(data) {
            const resultDiv = document.getElementById("result");
            resultDiv.innerHTML = ""; // 이전 결과 지우기

            if (data.message) {
                resultDiv.innerText = data.message;
                return;
            }

            // 프로필 아이콘 표시
            const profileImg = document.createElement("img");
            profileImg.src = data.profileIconLink;
            profileImg.alt = "프로필 아이콘";
            profileImg.style.width = "50px";
            profileImg.style.height = "50px";
            resultDiv.appendChild(profileImg);

            // 유저 정보 표시
            const userInfoHtml = `
                <h2>${data.summonerLevel} 레벨</h2>
                <p>최종 수정일: ${new Date(data.revisionDate).toLocaleString()}</p>
                <h3>리그 정보</h3>
                <ul>
                    ${data.league.map(entry => `
                        <li>${entry.tier} ${entry.rank} - 승: ${entry.wins}, 패: ${entry.losses}</li>
                    `).join('')}
                </ul>
                <p>선호 포지션: ${data.preferredPosition}</p>
                <h3>상위 챔피언</h3>
                <ul>
                    ${data.topChampions.map(champion => `
                        <li>
                            <img src="${champion.championImage}" alt="${champion.championName}" style="width: 30px; height: 30px;">
                            ${champion.championName}
                        </li>
                    `).join('')}
                </ul>
            `;

            resultDiv.innerHTML += userInfoHtml;
        }
    </script>
</body>
</html>

 


실행 화면

http://127.0.0.1:8000/api/profile/riotPage/ 이동
유저 정보 입력
조회 클릭!

 


Riot API Key 관리하는법

 

참고로 Riot api key는 외부에 절대 노출되면 안되기 때문에

settings.py에 config.py라는 파일을 만들어서

config.py

RIOT_API_KEY = 'your_riot_key_here'

 

settings.py

from . import config

RIOT_API_KEY = config.RIOT_API_KEY

 

.gitignore

config.py

 

깃허브에 노출되면 안되기 때문에 이런식으로 관리하였다.


관련 게시글

https://kimwoolina.tistory.com/136

 

[RIOT API] 라이엇 API 사용하는법 1. Production API Key 발급 받기 / 라이엇 계정으로 로그인(RSO)? - Secret C

먼저 개발자 API key 를 발급받자.https://developer.riotgames.com/ Riot Developer PortalAbout the Riot Games API With this site we hope to provide the League of Legends developer community with access to game data in a secure and reliable way. Thi

kimwoolina.tistory.com

 

https://kimwoolina.tistory.com/137

 

[RIOT API] 2. 유저이름, 유저태그로 puuid 발급 (account-v1)

https://developer.riotgames.com/apis Riot Developer Portal developer.riotgames.com라이엇 API는 여기에 정리 되어있다!  소환사명 + 태그로 puuid 발급 받기라이엇 API는 대부분 원하는 정보를 바로 얻을 수 없고,대

kimwoolina.tistory.com

 

https://kimwoolina.tistory.com/138

 

[RIOT API] 3. 유저네임으로 소환사정보(프로필 아이콘 이미지, 레벨) 가져오기 (summoner-v4)

https://kimwoolina.tistory.com/136 [RIOT API] 라이엇 API 사용하는법 1. Production API Key 발급 받기 / 라이엇 계정으로 로그인(RSO)? - Secret C먼저 개발자 API key 를 발급받자.https://developer.riotgames.com/ Riot Developer P

kimwoolina.tistory.com

 

https://kimwoolina.tistory.com/139

 

[RIOT API] 4. 유저네임으로 소환사 리그정보(랭크,티어 등) 조회하기 (league-v4)

https://developer.riotgames.com/apis#league-v4/GET_getLeagueEntriesForSummoner Riot Developer Portal developer.riotgames.com /lol/league/v4/entries/by-summoner/{encryptedSummonerId} 을 이용해보겠다. Return Value이 전 포스팅까지 썼던 api

kimwoolina.tistory.com