<SYSTEM_TASK:>
Given the following text description, write Python code to implement the functionality described below step by step
<END_TASK>
<USER_TASK:>
Description:
 LeagueRank
Step1:  To use the Riot api, one more important thing to do is to get your own API key. API key can be obtained from here. Note that normal developr API key has a narrow request limit, whereas production API key for commercial use has a looser requirement of request limit. For now, we are just gonna use the normal API key for demonstration.
After getting your own API key, put it in the config dictionary below
Step2:  <a name="architecture"></a>Project Architecture
<a name="crawl"></a>Data Crawling
The architecture for data crawler is shown as follow
Step3:  get_tier will return a divisioin dictionary, whose keys are the tier name, and values are the summoner id list in each tier. The results are printed in a human-readable format, categorized by tier.
Step4:  <a name="mfpChampions"></a>2. Fetch most frequently played champions
Since we already had a dictionary of all user ids mapping to all categories of ranks, we can now use those user ids to get the stats data of their most frequently used champions. We will use the raw RESTful APIs of Riot with python here. And here are all the libraries needed in this process.
Step5:  Then we can move on and fetch the data we need. Riot gives us the API to get all champions that a user had used during the season. And the response will be in JSON format. After parsing the JSON response, what we need to do is to get the most frequently used champions which can represent a player's level. So we sort the champions list by the number of games that the player used this champioin (totalSessionsPlayed) in descending order. Notice that the first element in the list will always be the champion with id 0, which represents the stats data of all champions that the player used in the season. So we need to skip that.
After we filter out the top frequently used champions of a user, we need to save the stats data with the player's tier as the training label into a csv file. In this project, each champion has a corresponding csv file which records all the stats data of this hero with the tier of the player as the training data. Since there are hundreds of champions in League of Legend, we will have hundreds of csv files for training and each file uses the id of champions as the file name. If the file is already created, we will append more stats of this champion to the csv file.
Step6:  With the above class, now we can start crawling the stats data of all champions saving them to csv files by the following code. Notice that this process is pretty slow since we added the sleep methods in our code. Riot APIs have a limitation on the API calls rate. You cannot send more than 500 requests per 10 minutes. So everytime we send a request here, we sleep for 1 second to prevent error responses.
<ASSISTANT_TASK:>
Python Code:
import csv
import json
import os
import ujson
import urllib2
from riotwatcher import RiotWatcher
Explanation: LeagueRank: A game skill evaluatioin application
<a name="introduction"></a>Introduction
Nowadays, League of Legends (LOL) is probably the most popular online MOBA game in the world, with over 67 million players every month. LOL is a real-time competing game, which requires skills and strategy. Thus, knowing about your ability and skills is important for people who want to reach a higher level, especially for the professional players. Currently, Riot Games (the producer of LOL) has only provided rank score to estimate the players integrated level. For specific champions' level, there's no official tools to precisely evaluate that. This project is aimed to reveal the players most frequently played champions' level and give players a guidance of how to horn his/her skills.
For background knowledge, there are some terminology that need to be clarified:
- Summoner: the player
- Champion: the character summoner uses during the game
- Tier: the level a summoner is in currently. There are seven tiers currently, from low to high: bronze, silver, gold, platinum, diamond, master and challenger.
- Division: the sub-level a summoner is in. For example, bronze to diamond have 5 divisions, represented using Roman numbers (I-V), whereas master and challenger have only one division.
Content
introduction
installing the library
project architecture
data crawling
fetch summoner list
fetch most frequently played champions
<a name="install"></a>Installing the library
Before getting started, we need to prepare some usful libraries. The main package we use to crawl the LOL data is called riotwatcher, which is a Python library built up with the API provided by Riot. To install the library, one common way using pip:
pip install riotwatcher
Although the library is robust and convenience, there are still some functions it does not implement such as getting the most frequently played champion, getting summoner list by tier, etc. To implement those functions, we are going to adopt corresponding Riot APIs, using urllib2 to request from the game server. Installing urllib2 via pip:
pip install urllib2
After you run all the installs, make sure the following commands work for you
End of explanation
config = {
    'key': 'API_key',
}
Explanation: To use the Riot api, one more important thing to do is to get your own API key. API key can be obtained from here. Note that normal developr API key has a narrow request limit, whereas production API key for commercial use has a looser requirement of request limit. For now, we are just gonna use the normal API key for demonstration.
After getting your own API key, put it in the config dictionary below:
End of explanation
class RiotCrawler:
    def __init__(self, key):
        self.key = key
        self.w = RiotWatcher(key)
        self.tiers = {
            'bronze': [],
            'silver': [],
            'gold': [],
            'platinum': [],
            'diamond': [],
            'challenger': [],
            'master': [],
        }
    # def get_player_list(self):
    #     recent_games = self.w.get_recent_games(self.player_id)
    #     player_list = set()
    #     for game in recent_games['games']:
    #         # only pick up ranked games
    #         if 'RANKED' in game['subType']:
    #             fellow_players = game['fellowPlayers']
    #             for fellow_player in fellow_players:
    #                 fellow_player_id = fellow_player['summonerId']
    #                 if fellow_player_id not in player_list:
    #                     player_list.add(fellow_player_id)
    #     return list(player_list)
    def get_player_by_tier(self, summoner_id):
        request_url = 'https://na.api.pvp.net/api/lol/na/v2.5/league/by-summoner/{}?api_key={}'.format(
            summoner_id, self.key
        )
        response = urllib2.urlopen(request_url)
        tier_info = ujson.loads(response.read())
        tier = tier_info[str(summoner_id)][0]['tier'].lower()
        entries = tier_info[str(summoner_id)][0]['entries']
        level = self.tiers[tier]
        for entry in entries:
            level.append(entry['playerOrTeamId'])
#         for l in level:
#             print 'summoner id: {}'.format(str(l))
Explanation: <a name="architecture"></a>Project Architecture
<a name="crawl"></a>Data Crawling
The architecture for data crawler is shown as follow:
The process of crawling data could be simplified as follows: 
1) Get summoners list from LOL server;
2) For each summoner, get his/her top 3 frequently played champions;
3) Fetch each champion's game stats for 2016 season (latest entire season);
4) Put the fetched data into corresponding csv file for storage.
<a name="summonerList"></a>1. Fetch summoner list
First of all, we need to fetch the summoner information down. Riot has provided with the api to get summoner information by leagues. League is the partial data in a tier. For example, in gold tier, we have summoners in gold I, gold II, gold III, gold IV and gold V. The summoners in gold tier are divided into several leagues, each league contains summoners in all ranges.
The __init__ method of RiotCrawler define the tiers, get_player_by_tier fetches the summoner list in different leagues according to the provided summoner ids.
End of explanation
def get_tier():
    # challenger: 77759242
    # platinum: 53381
    # gold: 70359816
    # silver: 65213225
    # bronze: 22309680
    # master: 22551130
    # diamond: 34570626
    player_ids = [70359816, 77759242, 53381, 65213225, 22309680, 22551130, 34570626]
    riot_crawler = RiotCrawler(config['key'])
    for player_id in player_ids:
        print 'start crawling id: {}'.format(player_id)
        riot_crawler.get_player_by_tier(player_id)
    return riot_crawler.tiers
tiers = get_tier()
for tier, rank_dict in tiers.iteritems():
    print '--- {} ---'.format(tier)
    for summoner in rank_dict:
        print 'summoner id: {}'.format(summoner)
    print '--- end of {} ---'.format(tier)
Explanation: get_tier will return a divisioin dictionary, whose keys are the tier name, and values are the summoner id list in each tier. The results are printed in a human-readable format, categorized by tier.
End of explanation
import csv
import json
import os
import urllib2
Explanation: <a name="mfpChampions"></a>2. Fetch most frequently played champions
Since we already had a dictionary of all user ids mapping to all categories of ranks, we can now use those user ids to get the stats data of their most frequently used champions. We will use the raw RESTful APIs of Riot with python here. And here are all the libraries needed in this process.
End of explanation
class TopChampion:
    FIELD_NAMES = ['totalSessionsPlayed', 'totalSessionsLost', 'totalSessionsWon',
                   'totalChampionKills', 'totalDamageDealt', 'totalDamageTaken',
                   'mostChampionKillsPerSession', 'totalMinionKills', 'totalDoubleKills',
                   'totalTripleKills', 'totalQuadraKills', 'totalPentaKills',
                   'totalUnrealKills', 'totalDeathsPerSession', 'totalGoldEarned',
                   'mostSpellsCast', 'totalTurretsKilled', 'totalPhysicalDamageDealt',
                   'totalMagicDamageDealt', 'totalFirstBlood', 'totalAssists',
                   'maxChampionsKilled', 'maxNumDeaths', 'label']
    def __init__(self, key, player_id, label, n):
        self.label = label
        self.player_id = player_id
        self.key = key
        self.n = n
        self.top_champions = []
        pass
    def get_top_champions(self):
        self.top_champions[:] = []
        data = urllib2.urlopen(
            'https://na.api.pvp.net/api/lol/na/v1.3/stats/by-summoner/' +
            self.player_id +
            '/ranked?season=SEASON2016&api_key=' +
            self.key
        ).read()
        json_data = json.loads(data)
        champions = json_data['champions']
        champion_stats = []
        for champion in champions:
            champion_stat = champion['stats']
            champion_stat['id'] = champion['id']
            champion_stat['label'] = self.label
            champion_stats.append(champion_stat)
            pass
        self.top_champions = sorted(champion_stats,
                                    key=lambda x: x['totalSessionsPlayed'],
                                    reverse=True)[1:self.n + 1]
        return self.top_champions
        pass
    def save_top_champions(self):
        for champion in self.top_champions:
            file_name = '../data/{}.csv'.format(champion['id'])
            if os.path.isfile(file_name):
                with open(file_name, 'a') as csvfile:
                    writer = csv.DictWriter(csvfile, fieldnames=self.FIELD_NAMES)
                    writer.writerow(
                        {
                            'totalSessionsPlayed': champion['totalSessionsPlayed'],
                            'totalSessionsLost': champion['totalSessionsLost'],
                            'totalSessionsWon': champion['totalSessionsWon'],
                            'totalChampionKills': champion['totalChampionKills'],
                            'totalDamageDealt': champion['totalDamageDealt'],
                            'totalDamageTaken': champion['totalDamageTaken'],
                            'mostChampionKillsPerSession': champion['mostChampionKillsPerSession'],
                            'totalMinionKills': champion['totalMinionKills'],
                            'totalDoubleKills': champion['totalDoubleKills'],
                            'totalTripleKills': champion['totalTripleKills'],
                            'totalQuadraKills': champion['totalQuadraKills'],
                            'totalPentaKills': champion['totalPentaKills'],
                            'totalUnrealKills': champion['totalUnrealKills'],
                            'totalDeathsPerSession': champion['totalDeathsPerSession'],
                            'totalGoldEarned': champion['totalGoldEarned'],
                            'mostSpellsCast': champion['mostSpellsCast'],
                            'totalTurretsKilled': champion['totalTurretsKilled'],
                            'totalPhysicalDamageDealt': champion['totalPhysicalDamageDealt'],
                            'totalMagicDamageDealt': champion['totalMagicDamageDealt'],
                            'totalFirstBlood': champion['totalFirstBlood'],
                            'totalAssists': champion['totalAssists'],
                            'maxChampionsKilled': champion['maxChampionsKilled'],
                            'maxNumDeaths': champion['maxNumDeaths'],
                            'label': champion['label']
                        }
                    )
                    pass
                pass
            else:
                with open(file_name, 'w') as csvfile:
                    writer = csv.DictWriter(csvfile, fieldnames=self.FIELD_NAMES)
                    writer.writeheader()
                    writer.writerow(
                        {
                            'totalSessionsPlayed': champion['totalSessionsPlayed'],
                            'totalSessionsLost': champion['totalSessionsLost'],
                            'totalSessionsWon': champion['totalSessionsWon'],
                            'totalChampionKills': champion['totalChampionKills'],
                            'totalDamageDealt': champion['totalDamageDealt'],
                            'totalDamageTaken': champion['totalDamageTaken'],
                            'mostChampionKillsPerSession': champion['mostChampionKillsPerSession'],
                            'totalMinionKills': champion['totalMinionKills'],
                            'totalDoubleKills': champion['totalDoubleKills'],
                            'totalTripleKills': champion['totalTripleKills'],
                            'totalQuadraKills': champion['totalQuadraKills'],
                            'totalPentaKills': champion['totalPentaKills'],
                            'totalUnrealKills': champion['totalUnrealKills'],
                            'totalDeathsPerSession': champion['totalDeathsPerSession'],
                            'totalGoldEarned': champion['totalGoldEarned'],
                            'mostSpellsCast': champion['mostSpellsCast'],
                            'totalTurretsKilled': champion['totalTurretsKilled'],
                            'totalPhysicalDamageDealt': champion['totalPhysicalDamageDealt'],
                            'totalMagicDamageDealt': champion['totalMagicDamageDealt'],
                            'totalFirstBlood': champion['totalFirstBlood'],
                            'totalAssists': champion['totalAssists'],
                            'maxChampionsKilled': champion['maxChampionsKilled'],
                            'maxNumDeaths': champion['maxNumDeaths'],
                            'label': champion['label']
                        }
                    )
                    pass
                pass
            pass
        pass
    pass
Explanation: Then we can move on and fetch the data we need. Riot gives us the API to get all champions that a user had used during the season. And the response will be in JSON format. After parsing the JSON response, what we need to do is to get the most frequently used champions which can represent a player's level. So we sort the champions list by the number of games that the player used this champioin (totalSessionsPlayed) in descending order. Notice that the first element in the list will always be the champion with id 0, which represents the stats data of all champions that the player used in the season. So we need to skip that.
After we filter out the top frequently used champions of a user, we need to save the stats data with the player's tier as the training label into a csv file. In this project, each champion has a corresponding csv file which records all the stats data of this hero with the tier of the player as the training data. Since there are hundreds of champions in League of Legend, we will have hundreds of csv files for training and each file uses the id of champions as the file name. If the file is already created, we will append more stats of this champion to the csv file.
End of explanation
def main():
    import time
    tiers = get_tier()
    for tier, rank_dict in tiers.iteritems():
        print 'starting tier: {}'.format(tier)
        for summoner_id in rank_dict:
            print 'tier: {}, summoner id: {}'.format(tier, summoner_id)
            top_champion = TopChampion(config['key'], summoner_id, tier, 3)
            top_champion.get_top_champions()
            top_champion.save_top_champions()
            time.sleep(1)
        print 'end tier: {}'.format(tier)
Explanation: With the above class, now we can start crawling the stats data of all champions saving them to csv files by the following code. Notice that this process is pretty slow since we added the sleep methods in our code. Riot APIs have a limitation on the API calls rate. You cannot send more than 500 requests per 10 minutes. So everytime we send a request here, we sleep for 1 second to prevent error responses.
End of explanation
<END_TASK>