#롤 기본 정보
주석 첫 줄에 적혀있듯 챔피언, 시즌, 큐타입 등 롤에 대한 기본적인 정보를 가져오는 부분입니다. 내부에 보면 keytochamp라는 변수가 있습니다. API를 쓰다보면 챔피언이 챔피언 이름이 아닌 번호로 나오는 경우가 많습니다({champin: 3} 이런식으로요). 그런 경우를 대비해 번호를 챔피언 이름으로 바꿔줄 때 쓰기위한 변수입니다.
다른 것들은 솔직히 어디에 쓰는지 잘 기억이 안납니다. 괜히 지웠다 어디 오류날까봐 수정 못하고 있습니다 ㅠㅠ
참고로 whole_champions = requests.get( ... ) 부분에 url 들어가 있는 부분에 보면 11.3.1이라고 되어있는데 그거 롤 버전입니다. 그래서 최소 신챔 나왔을 때는 저 부분을 최신 버전에 맞게 수정해줘야합니다. 안그러면 게임 기록에는 신챔 번호가 있는데 keytochamp에는 신챔이 없어서 오류가 발생할 수 있습니다.
#챔피언, 시즌, 큐타입 등 롤에대한 기본적인 정보를 가져옵니다.
#keytochamp={챔피언key:챔피언이름}
def phase1():
print('롤 기본 데이터 수집')
#챔피언 이상한 정보도 들어있는 드래곤 딕딕딕구조 {키:{},키:{}}
#dict_keys(['type', 'format', 'version', 'data'])
global keytochamp
keytochamp={}
#버전바뀔때마다 교체해줘야합니다. 적어도 신챔 나올때는 교체해줘야됩니다.
#http://ddragon.leagueoflegends.com/cdn/10.2.1/data/ko_KR/champion.json -> http://ddragon.leagueoflegends.com/cdn/11.3.1/data/ko_KR/champion.json
whole_champions=requests.get("http://ddragon.leagueoflegends.com/cdn/11.3.1/data/ko_KR/champion.json").json()
for champ in list(whole_champions['data'].keys()):
keytochamp[whole_champions['data'][champ]['key']]=whole_champions['data'][champ]['name']
#시즌정보 / [{}]
season_data = requests.get("http://static.developer.riotgames.com/docs/lol/seasons.json").json()
#큐타입정보[{}]
#{'queueId': 420, 'map': "Summoner's Rift", 'description': '5v5 Ranked Solo games'}
queqe_data = requests.get("http://static.developer.riotgames.com/docs/lol/queues.json").json()
###################여기까지기본정보받아오는곳
#소환사명을 인자로 받고 해당 계정의 accountId를 리턴합니다.
계정의 아이디를 accountId로 바꾸는 부분입니다. 여기서 말고는 API 사용에 있어 닉네임은 거의 사용이 되지 않습니다.
거의 모든 게 accountId를 요구합니다.
#계정의 게임아이디를 accountId로 바꿉니다
#가령 우주짱짱맨 -> ABCD-1234-ASDF 이런식입니다
#accountId가 있어야 해당 계정의 게임 내역을 가져올 수 있습니다.
def summonerName_to_accountId(summonerName):
#print(summonerName,'의 accountId 요청')
global api_key
url = 'https://kr.api.riotgames.com/lol/summoner/v4/summoners/by-name/'+summonerName+'?api_key='+api_key
base_data = req_api(url)
return base_data['accountId']
#계정의 accountId를 인자로 받고 해당 계정의 가장 최근 게임의 gameId를 리턴합니다.
각각의 판마다 고유한 gameId를 가지고 있습니다. 이걸 가지고 누가 이겼는지, 챔피언은 뭐가 등장했는지 등을 알 수 있습니다. 각각의 판에 부여되는 ID라 이걸 가지고 중복자료를 검토할 수도 있습니다. 여러모로 중요한 부분입니다.
#계정의 게임 기록들을 가져옵니다.
def from_accountId_get_gameid(accountId):
#print('gameid 가져오는중')
#url = 'https://kr.api.riotgames.com/lol/match/v4/matchlists/by-account/'+accountId+'?queue=420&endIndex='+str(endindex)+'&beginIndex='+str(beginindex)+'&api_key='+api_key
url ='https://kr.api.riotgames.com/lol/match/v4/matchlists/by-account/'+accountId+'?queue=420&api_key='+api_key
#gameids.json이 이미 있다면 가져오고 없다면 생성하여 가져옵니다. 중복자료 처리에 사용됩니다.
try:
gameids=load_json('gameids')
except:
write_json('gameids',[])
gameids = load_json('gameids')
data = req_api(url)
if data!=0 and data!=-1:
#계정의 게임 기록들은 data라는 dict의 'matches'라는 key로 접근합니다
for i in range(len(data['matches'])):
gameid = data['matches'][i]['gameId']
#5대5 게임인점, 유저를 먼저 모으고 각 유저의 게임기록을 살펴보는점 때문에 이미 조사한 게임이 중복되서 들어오는 경우가 생깁니다.
#gameids.json은 그런 문제를 해결합니다. 이미 gameids에 있는 gameid라면 continue합니다.
if gameid in gameids:
continue
else:
#중복자료가 아니고 이번 버전에서 행해진 게임이라면 gameids에 기록하여 다음 중복자료 탐색에 사용하고 str타입으로 gameid를 리턴합니다.
#gameid는 여러개 받아와도 하나만 사용하는 이유는 최대한 다양한 유저의 자료를 사용해야 치우침이 없을 것 같았습니다.
gameids.append(gameid)
write_json('gameids',gameids)
#매 패치마다 수정해야하는 부분입니다. 에포크밀리초로 지난 패치시점의 게임기록은 기록하지 않습니다.
#https://www.epochconverter.com/
if data['matches'][i]['timestamp']<1612342840000:
print("얘꺼 이번패치 기록 끝")
return 3
return str(gameid)
else:
print("얘꺼다봄######################################################")
return 0
else:
return 0
#gameids를 인자로 받아 해당 gameid를 가진 판에서 누가 원딜이었고 누가 서폿이었는지 반환합니다.
-아래 get_bottom_final과 get_bottom_full과 세트입니다.
-get_bottom_full은 보기 편하려고 만들었습니다.
-라인전이 이뤄지는 15분 정도까지의 각 플레이-어의 시간대별 위치 좌표를 받고
-바텀에 있으면 bot_point를 1올려 bot_point가 가장 높은 사람 둘이 바텀 라이너들이라고 정하는 방식입니다
-원딜과 서폿의 구분은 씨에스의 양으로 구분했습니다.
-바텀 뿐만 아니라 탑, 미드, 정글 등도 같은 원리로 구분했습니다.(get_mid_full(), get_top_full())
-미드와 정글 구분이 힘들었는데 15분까지 정글 몬스터를 가장 많이 잡은 유저를 정글러로 분류했습니다.
def get_bottom_base(gameid):
#print('phase5')
global api_key
#일단 데이터 요청
url = 'https://kr.api.riotgames.com/lol/match/v4/timelines/by-match/'+gameid+'?api_key='+api_key
#position = req_api(url)
#position['frames']에 시간별 위치정보 들어있음
frames=position['frames']
dongsun = {}
#participantid는 게임내 참여자 참가번호같은거
#dongsun['participantid'] ={1분:x,y, 2분:x,y} 이런식으로 저장
for frame in frames:
#print(frame['timestamp'])
partiframe = frame['participantFrames']
for pf in list(partiframe.keys()):
participantid = str(partiframe[pf]['participantId'])
if participantid not in dongsun.keys():
dongsun[participantid]=[]
if 'position' not in partiframe[pf].keys():
continue
#print(pf,partiframe[pf]['position'])
dongsun[participantid].append(partiframe[pf]['position'])
#여기부터 ptl.show()까지 시각화
#for i in range(1,11):
# i=str(i)
# for j in dongsun[i]:
# if i=='3':
# plt.scatter(j['x'],j['y'],c='b')
# elif i=='10':
# plt.scatter(j['x'],j['y'],c='b')
# else:
# plt.scatter(j['x'],j['y'],c='b')
#
#plt.show()
#member에 플레이어들 저장할껀데 어떻게 저장할꺼냐면 [바텀점수,바텀점수-딴라인점수,participantid] 이렇게
member = []
#i는 participantid
for i in range(1,11):
i=str(i)
#i번 플레이어가 바텀 라인에 있었을경우 계수하기위한 변수 botpoint
botpoint=0
#botpoint의 반대
elsepoint=0
#몇분시점인지 count로 체크
count=0
#dongsun[i][j]는 j시점 i번 플레이어의 위치
for j in dongsun[i]:
count+=1
#15분까지의 위치좌표만 보도록 하겠습니다. 이후에는 라인전이 끝나기때문입니다.
if count>12:
break
#바텀좌표에 있었으면 botpoint에 +1
if (j['x']>10000 and j['y']<5000) or (j['x']<10000 and j['y']<2000) or (j['x']>13000 and j['y']>0):
botpoint+=1
else:
elsepoint+=1
#이렇게 나온 botpoint,botpoint-elsepoint,i를 member에 저장
member.append([botpoint,botpoint-elsepoint,i])
#member를 botpoint 기준으로 오름차순 정렬
member.sort()
#결과에 get_bot()함수의 인자인 gameid 넣어두고
result = [gameid]
#botpoint 상위 네명의 participantid를 result에 넣는다
#pop()이 리스트의 마지막 요소를 꺼내주는 메소드고 [-1]은 아까 member 양식인[botpoint,botpoint-elsepoint,i]에서 i 즉 participantid
#결론적으로 gameid와 botpoint상위 네명의 participantid가 result에 들어가게된다
for i in range(4):
result.append(member.pop()[-1])
if len(result)!=5:
return 0
check = result[1:]
frame = frames[-1]
participantFrames = frame['participantFrames']
know_cs = {}
for pf in participantFrames.keys():
for pid in check:
if str(participantFrames[pf]['participantId'])==pid:
#봇과 봇씨에스가 맞게 나오나 보려면 해제
#print(pid,participantFrames[pf]['minionsKilled']+participantFrames[pf]['jungleMinionsKilled'])
know_cs[pid]=participantFrames[pf]['minionsKilled']+participantFrames[pf]['jungleMinionsKilled']
return result,know_cs
def get_botttom_final(bot):
#print('phase6')
#gameid는 gameid에
gameid = bot[0][0]
#여기부터 서폿둘 원딜둘 따로나누는부분
botcombi=bot[1]
bot = []
for i in botcombi.keys():
bot.append([botcombi[i],i])
bot.sort()
supports = bot[:2]
adcs = bot[2:]
#여기까지 서폿둘 원딜둘 따로나눔, 이상자료면 원딜 여러명될수도있음
#url = 'https://kr.api.riotgames.com/lol/match/v4/matches/'+gameid+'?api_key='+api_key
#data = req_api(url)
data = ffdata
teama =data['teams'][0]
teamb =data['teams'][1]
###승리팀구분, 한쪽만 이기지않으면 오류
#승리팀들어갈곳
winteam = 0
if (teama['win']=='Fail' and teamb['win']=='Win') or (teama['win']=='Win' and teamb['win']=='Fail'):
if teama['win']=='Win':
winteam=teama['teamId']
else:
winteam=teamb['teamId']
else:
return 0
###
adc_result =[]
for adc in adcs:
pid = adc[1]
for pt in data['participants']:
if str(pt['participantId']) ==pid:
adc_result.append([pt['teamId'],keytochamp[str(pt['championId'])]])
spt_result =[]
for spt in supports:
pid = spt[1]
for pt in data['participants']:
if str(pt['participantId']) ==pid:
spt_result.append([pt['teamId'],keytochamp[str(pt['championId'])]])
lastdata = []
for i in adc_result:
if i[0]==100:
lastdata.append(i)
for i in spt_result:
if i[0]==100:
lastdata.append(i)
for i in adc_result:
if i[0]==200:
lastdata.append(i)
for i in spt_result:
if i[0]==200:
lastdata.append(i)
lastdata.append(winteam)
t1=0
t2=0
for i in lastdata[:-1]:
if i[0]==100:
t1+=1
elif i[0]==200:
t2+=1
else:
print('이상 팀 정보')
return 0
if t1!=2 or t2!=2:
print('이상 팀 정보')
return 0
if lastdata[-1]!=100 and lastdata[-1]!=200:
print('이상 팀 정보')
return 0
'''
###여기부터
try:
new_before = load_json('new_before')
except:
write_json('new_before',[])
new_before = load_json('new_before')
new_before.append(lastdata)
write_json('new_before',new_before)
##여기까지 삭제예정
'''
return lastdata
def get_bottom_full(gameid):
#print('바텀 정보 분석중')
return get_botttom_final(get_bottom_base(gameid))
다른 라이너에 대한 코드는 원리가 같으니 여기에는 올리지 않겠습니다(맨 뒤 코드 전문 올리는 글에는 있습니다).
- get_mid_full() <<미드 정글,
- get_top_full()<<탑
두 함수가 다른 라이너에 대한 코드들입니다.
#인자: 원하는 티어의 정보, 리턴: 해당 티어 유저 4000명의 닉네임(소환사명)
게임을 가져오려면 유저가 필요하겠죠? 한 4000명 정도면 훌륭한 표본이라고 생각해 4000명의 아이디를 수집하는 함수를 만들었습니다.
get_4000(metal) 함수의 인자에 원하는 티어금속("BRONZE", "SILVER", "GOLD", ...)을 넣으면 get_user()함수가 해당 티어 1,2,3,4에 속하는 유저를 각각 1000명씩 모읍니다.
가령, get_4000("GOLD")를 실행하면,
- 골드1 유저 1000명
- 골드2 유저 1000명
- 골드3 유저 1000명
- 골드4 유저 1000명
을 모읍니다. 완성된 4000명의 유저 리스트는 순서가 랜덤하게 섞여서 리턴됩니다.
#아래 함수 get_4000과 세트입니다. 분석대상인 자료를 수집하는 부분입니다.
#조사를 원하는 metal의 tier1/2/3/4를 1000명씩 수집해 4000명을 만들었습니다.
def get_user(metal,tier,personnel):
global api_key
page=1
player_list = []
while True:
url = 'https://kr.api.riotgames.com/lol/league/v4/entries/RANKED_SOLO_5x5/'+metal+'/'+tier+'?page='+str(page)+'&api_key='+api_key
base_data = req_api(url)
if len(base_data)==0:
print(metal+tier+'유저가 부족하여 목표치인'+str(personnel)+'보다 적은'+str(len(player_list))+'만 수집 후 리턴')
return player_list
for i in range(len(base_data)):
player_list.append(base_data[i]['summonerName'])
if len(player_list)==personnel:
return player_list
page+=1
def get_4000(metal):
IV_1000 = get_user(metal,"IV",1000)
III_1000 = get_user(metal,"III",1000)
II_1000 = get_user(metal,"II",1000)
I_1000 = get_user(metal,"I",1000)
whole = IV_1000+III_1000+II_1000+I_1000
random_whole = whole[:]
random.shuffle(random_whole)
return random_whole
다했네요~
이번 글에서는 롤 분석기(수집기)에서 Riot API를 사용하는 함수들에 대해 말씀드려봤습니다.
다음 글에는 이 함수들이 어떻게 맞물려 돌아가는지 말씀드리도록 하겠습니다.
'게임 > 리그오브레전드 - Riot API' 카테고리의 다른 글
리그오브레전드 게임 데이터 수집기 만들기 [5화(完): 데이터 수집기 코드 전문] (0) | 2021.02.15 |
---|---|
리그오브레전드 게임 데이터 수집기 만들기 [4-3화: 데이터 수집기_관리용 함수들] (0) | 2021.02.14 |
리그오브레전드 게임 데이터 수집기 만들기 [4-1화: 데이터 수집기_Riot-API 사용 함수들] (0) | 2021.02.13 |
리그오브레전드 게임 데이터 수집기 만들기 [3화: 데이터 수집기_Riot-API 비사용 함수들] (0) | 2021.02.13 |
리그오브레전드 게임 데이터 수집기 만들기 [2화: Riot API - 사용권한 얻기] (0) | 2021.02.12 |