async def stalk_toornament_team( toornament_team_link: str, session: aiohttp.ClientSession = None ): """ Stalks all players in the given team and returns a Team Object :raises ServerErrorResponseError, NotFoundResponseError :param toornament_team_link: Link to a toornament team page :type toornament_team_link: str :param session: A session that can be reused, if none is given, a new one will be created :type session: aiohttp.ClientSession :return: team containing all players of the given team :rtype: Team """ if session is None: async with aiohttp.ClientSession() as session: return await stalk_toornament_team(toornament_team_link, session) edited_url = toornament_team_link + "info" async with session.get(edited_url) as response: if response.status >= 500: logger.error(f"Stalking {edited_url} resulted in a server error.") raise ServerErrorResponseError # check if toornament page was valid if response.status == 404: logger.error(f"No team could be found for {edited_url}.") raise NotFoundResponseError page = await response.text() toornament_soup = bs4.BeautifulSoup(page, features="html.parser") # extract team name team_name = toornament_soup.select( "#main-container > div.layout-section.header > div > div.layout-block.header > " "div > div.title > div > span" )[0].text name_containers = toornament_soup.find_all( "div", class_="text secondary small summoner_player_id" ) players = [] for container in name_containers: dirty_string = container.text dirty_split = dirty_string.split(":") # In case someone decides not to enter an actual summoner name if len(dirty_split) == 2: name = dirty_split[1] else: continue name = name.replace("\n", "") name = name.strip() players.append(Player(name)) return Team(team_name, players)
async def test_positive_stalk_player_op_gg(): from PykeBot2.backend.stalker import op_gg_rank from PykeBot2.models.data_models import Player, Rank test_player = Player("UFF NiceToMeetMe") test_rank = Rank(rank_string=await op_gg_rank.stalk_player_op_gg(test_player.summoner_name)) assert str(test_rank) == "Platinum 1"
async def stalk_battlefy_tournament(battlefy_url: str): """ Uses undocumented Battlefy API to scrape tournament participants. :param battlefy_url: A valid url to a battlefy tournament. :type battlefy_url: str :return: a TeamList object containing all Teams and Players of the given tournament. :rtype: TeamList """ # extract tournament id from url battlefy_url_split = battlefy_url.split("/") tournament_id = battlefy_url_split[5] # create link for http request by inserting the tournament id tournament_api_url = ( f"https://dtmwra1jsgyb0.cloudfront.net/tournaments/{tournament_id}/teams?" ) # make the request async with aiohttp.ClientSession() as session: async with session.get(tournament_api_url) as response: page = await response.text() # parse the data to create Team and Player Objects soup = bs4.BeautifulSoup(page, features="html.parser") json_data = json.loads(soup.text) # print(json.dumps(json_data, indent=4, separators=(". ", " = "))) teams = [] for team in json_data: team_name = team["name"] players = [] for player in team["players"]: player_name = player["inGameName"] player_obj = Player(player_name) # ranks are often not up to date so just normal rank addition for now # try to add rank if player stats are available # player_stats = player.get("stats", None) # if player_stats is not None: # player_rank_str = player_stats["tier"] + " " + player_stats["rank"] # player_rank = Rank(rank_string=player_rank_str) # player_obj.rank = player_rank players.append(player_obj) new_team = Team(team_name, players) # calc_average_and_max_team_rank(new_team) teams.append(new_team) team_list = TeamList(battlefy_url_split[4], teams) return team_list
async def stalk_prime_league_team(prime_league_team_link: str, session: aiohttp.ClientSession = None): """ :description: Uses aiohttp requests to stalk a prime league team. :param prime_league_team_link: :type prime_league_team_link: :param session: When a session already exits, it should be reused as much as possible for better performance. :type session: aiohttp.ClientSession :return: Team object containing all the gathered information. :rtype: Team """ if session is None: async with aiohttp.ClientSession() as session: return await stalk_prime_league_team(prime_league_team_link, session) async with session.get(prime_league_team_link) as response: # TODO add error handling page = await response.text() # Select Teammitglieder Container and find team name soup = bs4.BeautifulSoup(page, features="html.parser") player_container = soup.find("ul", class_="content-portrait-grid-l") # check if the team was deleted if player_container is None: return None team_container = soup.find("div", class_="content-portrait-head") # behind the team name is always " « League Teams « Prime League", which needs to be removed # this solution will fail if a team uses « in their name team_name = soup.title.text.split("«")[0].strip() # extract player names player_boxes = player_container.find_all("li") tuple_list = [] for box in player_boxes: confirmed = box.find("span", class_="txt-status-positive") player_info = box.find( "span", title="League of Legends » LoL Summoner Name (EU West)") tuple_list.append((player_info, confirmed)) # create Team object and filter out unconfirmed player player_names = [] confirmed_check = "Bestätigter Spieler" for player, confirm in tuple_list: if confirm is not None and confirm.text == confirmed_check: player_obj = Player(player.text) player_names.append(player_obj) return Team(team_name, player_names)
async def add_player_rank(player: Player, session: aiohttp.ClientSession = None): """ :description: Calls stalk player op gg using the summoner name of the given Player and adds a Rank obj to the Player. :param player: A Player obj with a summoner name. :type player: Player :param session: When a session already exits, it should be reused as much as possible for better performance. :type session: aiohttp.ClientSession :return: None :rtype: None """ if session is None: async with aiohttp.ClientSession() as session: return await add_player_rank(player, session) player.rank = Rank( rank_string=await stalk_player_op_gg(player.summoner_name, session)) return
def parse_participants(participants: List[dict], tournament_name: str) -> TeamList: """ Parses the given participant list and tournament name to create a TeamList object. :param participants: Expects a participant list created from the toornament api. :type participants: list[dict] :param tournament_name: The name of the tournament. :type tournament_name: str :return: A TeamList object created from the given participant list and tournament name. :rtype: TeamList """ total = {} for team in participants: total[team["id"]] = team teams = [] for team_entry in total.values(): team_name = team_entry["name"] team_lineup = team_entry["lineup"] players = [] for lineup_entry in team_lineup: custom_fields = lineup_entry["custom_fields"] keys = custom_fields.keys() summoner_name_field = None for key in keys: if "summoner" in key: summoner_name_field = key break if summoner_name_field is None: # if summoner_name_field is private or not set, try using the name player_summoner_name = lineup_entry["name"] else: player_summoner_name = lineup_entry["custom_fields"][ summoner_name_field] if player_summoner_name is None: continue player = Player(player_summoner_name) players.append(player) team = Team(team_name, players) teams.append(team) team_list = TeamList(tournament_name, teams) return team_list
async def add_player_rank(player: Player, api_token: str, session=None): """ :description: Calls stalk player riot using the summoner name of the given Player and adds a Rank obj to the Player. :param player: A Player obj with a summoner name. :type player: Player :param api_token: Valid Riot api token. :type api_token: str :param session: When a session already exits, it should be reused as much as possible for better performance. :type session: aiohttp.ClientSession or RateLimiter :return: None :rtype: None """ if session is None: async with aiohttp.ClientSession() as session: session = RateLimiter(session) return await add_player_rank(player, api_token, session) player.rank = Rank(rank_string=await stalk_player_riot_api( player.summoner_name, api_token, session)) return