Beispiel #1
0
def bl_parse_stats(parsed, mode="quickplay"):
    # Just a quick FYI
    # If future me or future anyone else is looking at this, I do not how this code works.
    # I'm really really hoping it doesn't break.
    # Good luck!

    try:
        # XPath for the `u-align-center` h6 which signifies there's no data.
        no_data = parsed.xpath(
            ".//div[@id='{}']//ul/h6[@class='u-align-center']".format(mode))[0]
    except IndexError:
        pass
    else:
        if no_data.text.strip(
        ) == "We don't have any data for this account in this mode yet.":
            return None

    # Start the dict.
    built_dict = {"game_stats": [], "overall_stats": {}, "average_stats": []}

    # Shortcut location for player level etc
    mast_head = parsed.xpath(".//div[@class='masthead-player']")[0]

    # Get the prestige.
    prestige = mast_head.xpath(".//div[@class='player-level']")[0]
    # Extract the background-image from the styles.
    try:
        bg_image = [x for x in prestige.values() if 'background-image' in x][0]
    except IndexError:
        # Cannot find background-image.
        # Yikes!
        # Don't set a prestige.
        built_dict["overall_stats"]["prestige"] = 0
    else:
        for key, val in PRESTIGE.items():
            if key in bg_image:
                prestige_num = val
                built_dict["overall_stats"]["rank_image"] = bg_image.split(
                    "(")[1][:-1]
                break
        else:
            # Unknown.
            prestige_num = None
        built_dict["overall_stats"]["prestige"] = prestige_num

    # Parse out the HTML.
    level = int(prestige.findall(".//div")[0].text)
    built_dict["overall_stats"]["level"] = level

    try:
        tier = mast_head.xpath(".//div[@class='competitive-rank']/img")[0]
        img_src = [x for x in tier.values() if 'rank-icons' in x][0]
    except IndexError:
        built_dict['overall_stats']['tier'] = None
    else:
        for key, val in tier_data_img_src.items():
            if key in img_src:
                tier_str = val
                break
        else:
            tier_str = None
        built_dict["overall_stats"]["tier"] = tier_str

    hasrank = mast_head.findall(".//div[@class='competitive-rank']/div")
    if hasrank:
        comprank = int(hasrank[0].text)
    else:
        comprank = None
    built_dict["overall_stats"]["comprank"] = comprank

    # Fetch Avatar
    built_dict["overall_stats"]["avatar"] = mast_head.find(
        ".//img[@class='player-portrait']").attrib['src']

    if mode == "competitive":
        hascompstats = parsed.xpath(
            ".//div[@data-group-id='stats' and @data-category-id='0x02E00000FFFFFFFF']"
        )
        if len(hascompstats) != 2:
            return None
        stat_groups = hascompstats[1]
    elif mode == "quickplay":
        try:
            stat_groups = parsed.xpath(
                ".//div[@data-group-id='stats' and @data-category-id='0x02E00000FFFFFFFF']"
            )[0]
        except IndexError:
            # User has no stats...
            return None
    else:
        # how else to handle fallthrough case?
        stat_groups = parsed.xpath(
            ".//div[@data-group-id='stats' and @data-category-id='0x02E00000FFFFFFFF']"
        )[0]

    # Highlight specific stat groups.
    try:
        game_box = stat_groups[6]
    except IndexError:
        try:
            game_box = stat_groups[5]
        except IndexError:
            # edge cases...
            # we can't really extract any more stats
            # so we do an early return
            return {}

    # Calculate the wins, losses, and win rate.
    try:
        wins = int(
            game_box.xpath(".//text()[. = 'Games Won']/../..")[0]
            [1].text.replace(",", ""))
    except IndexError:
        # weird edge case
        wins = 0
    g = game_box.xpath(".//text()[. = 'Games Played']/../..")
    if len(g) < 1:
        # Blizzard f****d up, temporary quick fix for #70
        games, losses = None, None
    else:
        games = int(g[0][1].text.replace(",", ""))

    if mode == "competitive":
        try:
            misc_box = stat_groups[7]
            losses = int(
                misc_box.xpath(".//text()[. = 'Games Lost']/../..")[0]
                [1].text.replace(",", ""))
            ties = int(
                misc_box.xpath(".//text()[. = 'Games Tied']/../..")[0]
                [1].text.replace(",", ""))
        except IndexError:
            # Sometimes the losses and ties don't exist.
            # I'm not 100% as to what causes this, but it might be because there are no ties.
            # In this case, just set ties to 0, and calculate losses manually.
            ties = 0
            # Quickplay shit.
            # Goddamnit blizzard.
            if games is None:
                losses = 0
                games = 0
                wins = 0
            else:
                # Competitive stats do have these values (for now...)
                losses = games - wins

        if games == 0 or games == ties:
            wr = 0
        else:
            wr = round((wins / (games - ties)) * 100, 2)

        built_dict["overall_stats"]["ties"] = ties
        built_dict["overall_stats"]["games"] = games
        built_dict["overall_stats"]["losses"] = losses
        built_dict["overall_stats"]["win_rate"] = wr

    # Update the dictionary.
    built_dict["overall_stats"]["wins"] = wins

    # Build a dict using the stats.
    _t_d = {}
    _a_d = {}
    for subbox in stat_groups:
        trs = subbox.findall(".//tbody/tr")
        # Update the dict with [0]: [1]
        for subval in trs:
            name, value = util.sanitize_string(subval[0].text), subval[1].text
            # Try and parse out the value. It might be a time!
            # If so, try and extract the time.
            nvl = util.try_extract(value)
            if 'average' in name.lower():
                _a_d[name.replace("_average", "_avg")] = nvl
            else:
                _t_d[name] = nvl

    # Manually add the KPD.
    try:
        _t_d["kpd"] = round(_t_d["eliminations"] / _t_d["deaths"], 2)
    except KeyError:
        # They don't have any eliminations/deaths.
        # Set the KPD to 0.0.
        # See: #106
        _t_d["kpd"] = 0

    built_dict["game_stats"] = _t_d
    built_dict["average_stats"] = _a_d
    built_dict["competitive"] = mode == "competitive"

    if not "games" in built_dict["overall_stats"]:
        # manually calculate it
        dmg_done = built_dict["game_stats"]["damage_done"]
        avg_dmgd = built_dict["average_stats"]["damage_done_avg"]

        # IT RETURNS
        games = int(dmg_done // avg_dmgd)

        losses = games - built_dict["overall_stats"]["wins"]
        built_dict["overall_stats"]["games"] = games
        built_dict["overall_stats"]["losses"] = losses
        built_dict["overall_stats"]["win_rate"] = round(
            (built_dict["overall_stats"]["wins"] / games) * 100, 2)

    return built_dict
Beispiel #2
0
async def bl_get_stats(mode, ctx, battletag):
    data = await bz.region_helper_v2(ctx, battletag, region=ctx.request.args.get("region", None),
                                     platform=ctx.request.args.get("platform", "pc"))
    if data == (None, None):
        raise HTTPException(404)

    parsed, region = data

    # Start the dict.
    built_dict = {"region": region, "battletag": battletag, "game_stats": [], "overall_stats": {}, "average_stats": []}

    # Get the prestige.
    prestige = parsed.xpath(".//div[@class='player-level']")[0]
    # Extract the background-image from the styles.
    try:
        bg_image = [x for x in prestige.values() if 'background-image' in x][0]
    except IndexError:
        # Cannot find background-image.
        # Yikes!
        # Don't set a prestige.
        built_dict["overall_stats"]["prestige"] = 0
    else:
        for key, val in PRESTIGE.items():
            if key in bg_image:
                prestige_num = val
                break
        else:
            # Unknown.
            prestige_num = None
        built_dict["overall_stats"]["prestige"] = prestige_num

    # Parse out the HTML.
    level = int(parsed.findall(".//div[@class='player-level']/div")[0].text)
    built_dict["overall_stats"]["level"] = level

    hasrank = parsed.findall(".//div[@class='competitive-rank']/div")
    if hasrank:
        comprank = int(hasrank[0].text)
    else:
        comprank = None
    built_dict["overall_stats"]["comprank"] = comprank

    # Fetch Avatar
    built_dict["overall_stats"]["avatar"] = parsed.find(".//img[@class='player-portrait']").attrib['src']

    if mode == "competitive":
        hascompstats = parsed.xpath(".//div[@data-group-id='stats' and @data-category-id='0x02E00000FFFFFFFF']")
        if len(hascompstats) != 2:
            return {"error": 404, "msg": "competitive stats not found", "region": region}, 404
        stat_groups = hascompstats[1]
    elif mode == "quickplay":
        stat_groups = parsed.xpath(".//div[@data-group-id='stats' and @data-category-id='0x02E00000FFFFFFFF']")[0]
    else:
        # how else to handle fallthrough case?
        stat_groups = parsed.xpath(".//div[@data-group-id='stats' and @data-category-id='0x02E00000FFFFFFFF']")[0]

    # Highlight specific stat groups.
    death_box = stat_groups[4]
    try:
        game_box = stat_groups[6]
    except IndexError:
        game_box = stat_groups[5]

    # Calculate the wins, losses, and win rate.
    try:
        wins = int(game_box.xpath(".//text()[. = 'Games Won']/../..")[0][1].text.replace(",", ""))
    except IndexError:
        # weird edge case
        wins = 0
    g = game_box.xpath(".//text()[. = 'Games Played']/../..")
    if len(g) < 1:
        # Blizzard f****d up, temporary quick fix for #70
        games, losses = 0, 0
        wr = 0
    else:
        games = int(g[0][1].text.replace(",", ""))
        losses = games - wins
        wr = floor((wins / games) * 100)

    # Update the dictionary.
    built_dict["overall_stats"]["games"] = games
    built_dict["overall_stats"]["losses"] = losses
    built_dict["overall_stats"]["wins"] = wins
    built_dict["overall_stats"]["win_rate"] = wr

    # Build a dict using the stats.
    _t_d = {}
    _a_d = {}
    for subbox in stat_groups:
        trs = subbox.findall(".//tbody/tr")
        # Update the dict with [0]: [1]
        for subval in trs:
            name, value = subval[0].text.lower().replace(" ", "_").replace("_-_", "_"), subval[1].text
            # Try and parse out the value. It might be a time!
            # If so, try and extract the time.
            nvl = util.try_extract(value)
            if 'average' in name.lower():
                _a_d[name.replace("_average", "_avg")] = nvl
            else:
                _t_d[name] = nvl

    # Manually add the KPD.
    _t_d["kpd"] = round(_t_d["eliminations"] / _t_d["deaths"], 2)

    built_dict["game_stats"] = _t_d
    built_dict["average_stats"] = _a_d
    built_dict["competitive"] = mode == "competitive"

    return built_dict
Beispiel #3
0
def bl_parse_stats(parsed, mode="quickplay"):
    # Start the dict.
    built_dict = {"game_stats": [], "overall_stats": {}, "average_stats": []}

    # Get the prestige.
    prestige = parsed.xpath(".//div[@class='player-level']")[0]
    # Extract the background-image from the styles.
    try:
        bg_image = [x for x in prestige.values() if 'background-image' in x][0]
    except IndexError:
        # Cannot find background-image.
        # Yikes!
        # Don't set a prestige.
        built_dict["overall_stats"]["prestige"] = 0
    else:
        for key, val in PRESTIGE.items():
            if key in bg_image:
                prestige_num = val
                break
        else:
            # Unknown.
            prestige_num = None
        built_dict["overall_stats"]["prestige"] = prestige_num

    # Parse out the HTML.
    level = int(parsed.findall(".//div[@class='player-level']/div")[0].text)
    built_dict["overall_stats"]["level"] = level

    hasrank = parsed.findall(".//div[@class='competitive-rank']/div")
    if hasrank:
        comprank = int(hasrank[0].text)
    else:
        comprank = None
    built_dict["overall_stats"]["comprank"] = comprank

    # Fetch Avatar
    built_dict["overall_stats"]["avatar"] = parsed.find(
        ".//img[@class='player-portrait']").attrib['src']

    if mode == "competitive":
        hascompstats = parsed.xpath(
            ".//div[@data-group-id='stats' and @data-category-id='0x02E00000FFFFFFFF']"
        )
        if len(hascompstats) != 2:
            return {}
        stat_groups = hascompstats[1]
    elif mode == "quickplay":
        stat_groups = parsed.xpath(
            ".//div[@data-group-id='stats' and @data-category-id='0x02E00000FFFFFFFF']"
        )[0]
    else:
        # how else to handle fallthrough case?
        stat_groups = parsed.xpath(
            ".//div[@data-group-id='stats' and @data-category-id='0x02E00000FFFFFFFF']"
        )[0]

    # Highlight specific stat groups.
    try:
        game_box = stat_groups[6]
    except IndexError:
        try:
            game_box = stat_groups[5]
        except IndexError:
            # edge cases...
            # we can't really extract any more stats
            # so we do an early return
            return {}

    # Calculate the wins, losses, and win rate.
    try:
        wins = int(
            game_box.xpath(".//text()[. = 'Games Won']/../..")[0]
            [1].text.replace(",", ""))
    except IndexError:
        # weird edge case
        wins = 0
    g = game_box.xpath(".//text()[. = 'Games Played']/../..")
    if len(g) < 1:
        # Blizzard f****d up, temporary quick fix for #70
        games, losses = None, None
        wr = 0
    else:
        games = int(g[0][1].text.replace(",", ""))
        losses = games - wins
        wr = floor((wins / games) * 100)

    # Update the dictionary.
    built_dict["overall_stats"]["games"] = games
    built_dict["overall_stats"]["losses"] = losses
    built_dict["overall_stats"]["wins"] = wins
    built_dict["overall_stats"]["win_rate"] = wr

    # Build a dict using the stats.
    _t_d = {}
    _a_d = {}
    for subbox in stat_groups:
        trs = subbox.findall(".//tbody/tr")
        # Update the dict with [0]: [1]
        for subval in trs:
            name, value = util.sanitize_string(subval[0].text), subval[1].text
            # Try and parse out the value. It might be a time!
            # If so, try and extract the time.
            nvl = util.try_extract(value)
            if 'average' in name.lower():
                _a_d[name.replace("_average", "_avg")] = nvl
            else:
                _t_d[name] = nvl

    # Manually add the KPD.
    _t_d["kpd"] = round(_t_d["eliminations"] / _t_d["deaths"], 2)

    built_dict["game_stats"] = _t_d
    built_dict["average_stats"] = _a_d
    built_dict["competitive"] = mode == "competitive"

    return built_dict
Beispiel #4
0
def bl_parse_stats(parsed, mode="quickplay"):
    # Just a quick FYI
    # If future me or future anyone else is looking at this, I do not how this code works.
    # I'm really really hoping it doesn't break.
    # Good luck!

    try:
        # XPath for the `u-align-center` h6 which signifies there's no data.
        no_data = parsed.xpath(".//div[@id='{}']//ul/h6[@class='u-align-center']".format(mode))[0]
    except IndexError:
        pass
    else:
        if no_data.text.strip() == "We don't have any data for this account in this mode yet.":
            return None

    # Start the dict.
    built_dict = {"game_stats": [], "overall_stats": {}, "average_stats": []}

    # Shortcut location for player level etc
    mast_head = parsed.xpath(".//div[@class='masthead-player']")[0]

    # Get the prestige.
    prestige = mast_head.xpath(".//div[@class='player-level']")[0]
    # Extract the background-image from the styles.
    try:
        bg_image = [x for x in prestige.values() if 'background-image' in x][0]
    except IndexError:
        # Cannot find background-image.
        # Yikes!
        # Don't set a prestige.
        built_dict["overall_stats"]["prestige"] = 0
    else:
        for key, val in PRESTIGE.items():
            if key in bg_image:
                prestige_num = val
                built_dict["overall_stats"]["rank_image"] = bg_image.split("(")[1][:-1]
                break
        else:
            # Unknown.
            prestige_num = None
        built_dict["overall_stats"]["prestige"] = prestige_num

    # Parse out the HTML.
    level = int(prestige.findall(".//div")[0].text)
    built_dict["overall_stats"]["level"] = level

    try:
        tier = mast_head.xpath(".//div[@class='competitive-rank']/img")[0]
        img_src = [x for x in tier.values() if 'rank-icons' in x][0]
    except IndexError:
        built_dict['overall_stats']['tier'] = None
    else:
        for key, val in tier_data_img_src.items():
            if key in img_src:
                tier_str = val
                break
        else:
            tier_str = None
        built_dict["overall_stats"]["tier"] = tier_str

    hasrank = mast_head.findall(".//div[@class='competitive-rank']/div")
    if hasrank:
        comprank = int(hasrank[0].text)
    else:
        comprank = None
    built_dict["overall_stats"]["comprank"] = comprank

    # Fetch Avatar
    built_dict["overall_stats"]["avatar"] = mast_head.find(
        ".//img[@class='player-portrait']"
    ).attrib['src']

    if mode == "competitive":
        # the competitive overview is under a div with id='competitive'
        # and the right category
        try:
            stat_groups = parsed.xpath(
                ".//div[@id='competitive']"
                "//div[@data-group-id='stats' and @data-category-id='0x02E00000FFFFFFFF']"
            )[0]
        except IndexError:
            # No stats
            return None
    elif mode == "quickplay":
        try:
            stat_groups = parsed.xpath(
                ".//div[@id='quickplay']"
                "//div[@data-group-id='stats' and @data-category-id='0x02E00000FFFFFFFF']"
            )[0]
        except IndexError:
            # User has no stats...
            return None
    else:
        # how else to handle fallthrough case?
        stat_groups = parsed.xpath(
            ".//div[@data-group-id='stats' and @data-category-id='0x02E00000FFFFFFFF']"
        )[0]

    # Highlight specific stat groups.
    try:
        game_box = stat_groups[6]
    except IndexError:
        try:
            game_box = stat_groups[5]
        except IndexError:
            # edge cases...
            # we can't really extract any more stats
            # so we do an early return
            return {}

    # Calculate the wins, losses, and win rate.
    try:
        wins = int(game_box.xpath(".//text()[. = 'Games Won']/../..")[0][1].text.replace(",", ""))
    except IndexError:
        # weird edge case
        wins = 0
    g = game_box.xpath(".//text()[. = 'Games Played']/../..")
    if len(g) < 1:
        # Blizzard f****d up, temporary quick fix for #70
        games, losses = None, None
    else:
        games = int(g[0][1].text.replace(",", ""))

    if mode == "competitive":
        try:
            misc_box = stat_groups[7]
            losses = int(misc_box.xpath(".//text()[. = 'Games Lost']/../..")[0][1].text
                         .replace(",", ""))
            ties = int(misc_box.xpath(".//text()[. = 'Games Tied']/../..")[0][1].text
                       .replace(",", ""))
        except IndexError:
            # Sometimes the losses and ties don't exist.
            # I'm not 100% as to what causes this, but it might be because there are no ties.
            # In this case, just set ties to 0, and calculate losses manually.
            ties = 0
            # Quickplay shit.
            # Goddamnit blizzard.
            if games is None:
                losses = 0
                games = 0
                wins = 0
            else:
                # Competitive stats do have these values (for now...)
                losses = games - wins

        if games == 0 or games == ties:
            wr = 0
        else:
            wr = round((wins / (games - ties)) * 100, 2)

        built_dict["overall_stats"]["ties"] = ties
        built_dict["overall_stats"]["games"] = games
        built_dict["overall_stats"]["losses"] = losses
        built_dict["overall_stats"]["win_rate"] = wr

    # Update the dictionary.
    built_dict["overall_stats"]["wins"] = wins

    # Build a dict using the stats.
    _t_d = {}
    _a_d = {}
    for subbox in stat_groups:
        trs = subbox.findall(".//tbody/tr")
        # Update the dict with [0]: [1]
        for subval in trs:
            name, value = util.sanitize_string(subval[0].text), subval[1].text
            # Try and parse out the value. It might be a time!
            # If so, try and extract the time.
            nvl = util.try_extract(value)
            if 'average' in name.lower():
                _a_d[name.replace("_average", "_avg")] = nvl
            else:
                _t_d[name] = nvl

    # Manually add the KPD.
    try:
        _t_d["kpd"] = round(_t_d["eliminations"] / _t_d["deaths"], 2)
    except KeyError:
        # They don't have any eliminations/deaths.
        # Set the KPD to 0.0.
        # See: #106
        _t_d["kpd"] = 0

    built_dict["game_stats"] = _t_d
    built_dict["average_stats"] = _a_d
    built_dict["competitive"] = mode == "competitive"

    if "games" not in built_dict["overall_stats"]:
        # manually calculate it
        # 2017-07-04 - changed to use eliminations
        # since damage done gave a bit of a stupid amount
        # 2017-07-11 - changed to cycle some averages
        average_keys = ("eliminations", "healing_done", "final_blows", "objective_kills")
        for key in average_keys:
            try:
                total = built_dict["game_stats"][key]
                avg = built_dict["average_stats"][key + "_avg"]
            except KeyError:
                continue
            else:
                got = True
                break
        else:
            got = False

        if got:
            games = int(total // avg)

            losses = games - built_dict["overall_stats"]["wins"]
            built_dict["overall_stats"]["games"] = games
            built_dict["overall_stats"]["losses"] = losses
            built_dict["overall_stats"]["win_rate"] = round(
                (built_dict["overall_stats"]["wins"] / games) * 100, 2
            )
        else:
            # lol make them up
            built_dict["overall_stats"]["games"] = 0
            built_dict["overall_stats"]["losses"] = 0
            built_dict["overall_stats"]["win_rate"] = 0

    return built_dict
Beispiel #5
0
def bl_parse_stats(parsed, mode="quickplay", status=None):
    # Just a quick FYI
    # If future me or future anyone else is looking at this, I do not how this code works.
    # I'm really really hoping it doesn't break.
    # Good luck!

    try:
        # XPath for the `u-align-center` h6 which signifies there's no data.
        no_data = parsed.xpath(
            ".//div[@id='{}']//ul/h6[@class='u-align-center']".format(mode))[0]
    except IndexError:
        pass
    else:
        if no_data.text.strip(
        ) == "We don't have any data for this account in this mode yet.":
            return None

    # Start the dict.
    built_dict = {"game_stats": [], "overall_stats": {}, "average_stats": []}

    # Shortcut location for player level etc
    if not status or status.lower() != "public profile":
        hasrank = parsed.xpath(
            '//*[@id="overview-section"]/div/div/div/div/div[2]/div/div[3]/div'
        )
        if hasrank:
            comprank = int(hasrank[0].text)
        else:
            comprank = None
        built_dict["overall_stats"]["comprank"] = comprank
        return built_dict

    mast_head = parsed.xpath(".//div[@class='masthead-player']")[0]

    # Get the prestige.
    prestige = mast_head.xpath(".//div[@class='player-level']")[0]
    # Extract the background-image from the styles.
    try:
        bg_image = [x for x in prestige.values() if 'background-image' in x][0]
    except IndexError:
        # Cannot find background-image.
        # Yikes!
        # Don't set a prestige.
        built_dict["overall_stats"]["prestige"] = 0
    else:
        for key, val in PRESTIGE.items():
            if key in bg_image:
                prestige_num = val
                built_dict["overall_stats"]["rank_image"] = bg_image.split(
                    "(")[1][:-1]
                break
        else:
            # Unknown.
            prestige_num = None
        built_dict["overall_stats"]["prestige"] = prestige_num

    # Parse out the HTML.
    level = int(prestige.findall(".//div")[0].text)
    built_dict["overall_stats"]["level"] = level

    # Get and parse out endorsement level.
    endorsement = mast_head.xpath(".//div[@class='endorsement-level']")[0]
    built_dict["overall_stats"]["endorsement_level"] = int(
        endorsement.findall(".//div[@class='u-center']")[0].text)

    # Get endorsement circle.
    endorsement_icon_inner = mast_head.xpath(
        ".//div[@class='endorsement-level']/div[@class='EndorsementIcon']/div[@class='EndorsementIcon-inner']"
    )[0]

    # Get individual endorsement segments.
    try:
        endorsement_shotcaller_image = endorsement_icon_inner.findall(
            ".//svg[@class='EndorsementIcon-border EndorsementIcon-border--shotcaller']"
        )[0]
        endorsement_shotcaller_level = endorsement_shotcaller_image.get(
            'data-value')
    except:
        endorsement_shotcaller_level = 0

    try:
        endorsement_teammate_image = endorsement_icon_inner.findall(
            ".//svg[@class='EndorsementIcon-border EndorsementIcon-border--teammate']"
        )[0]
        endorsement_teammate_level = endorsement_teammate_image.get(
            'data-value')
    except:
        endorsement_teammate_level = 0

    try:
        endorsement_sportsmanship_image = endorsement_icon_inner.findall(
            ".//svg[@class='EndorsementIcon-border EndorsementIcon-border--sportsmanship']"
        )[0]
        endorsement_sportsmanship_level = endorsement_sportsmanship_image.get(
            'data-value')
    except:
        endorsement_sportsmanship_level = 0

    # Parse out endorsement segements.
    built_dict["overall_stats"][
        "endorsement_shotcaller"] = endorsement_shotcaller_level
    built_dict["overall_stats"][
        "endorsement_teammate"] = endorsement_teammate_level
    built_dict["overall_stats"][
        "endorsement_sportsmanship"] = endorsement_sportsmanship_level

    # Get comp rank.
    try:
        tier = mast_head.xpath(".//div[@class='competitive-rank']/img")[0]
        img_src = [x for x in tier.values() if 'rank-icons' in x][0]
        built_dict["overall_stats"]["tier_image"] = img_src
    except IndexError:
        built_dict['overall_stats']['tier'] = None
    else:
        for key, val in tier_data_img_src.items():
            if key in img_src:
                tier_str = val
                break
        else:
            tier_str = None
        built_dict["overall_stats"]["tier"] = tier_str

    hasrank = mast_head.findall(".//div[@class='competitive-rank']/div")
    if hasrank:
        comprank = int(hasrank[0].text)
    else:
        comprank = None
    built_dict["overall_stats"]["comprank"] = comprank

    # Fetch Avatar
    built_dict["overall_stats"]["avatar"] = mast_head.find(
        ".//img[@class='player-portrait']").attrib['src']

    if mode == "competitive":
        # the competitive overview is under a div with id='competitive'
        # and the right category
        try:
            stat_groups = parsed.xpath(
                ".//div[@id='competitive']"
                "//div[@data-group-id='stats' and @data-category-id='0x02E00000FFFFFFFF']"
            )[0]
        except IndexError:
            # No stats
            return None
    elif mode == "quickplay":
        try:
            stat_groups = parsed.xpath(
                ".//div[@id='quickplay']"
                "//div[@data-group-id='stats' and @data-category-id='0x02E00000FFFFFFFF']"
            )[0]
        except IndexError:
            # User has no stats...
            return None
    else:
        # how else to handle fallthrough case?
        stat_groups = parsed.xpath(
            ".//div[@data-group-id='stats' and @data-category-id='0x02E00000FFFFFFFF']"
        )[0]

    # Highlight specific stat groups.
    try:
        game_box = stat_groups[5]
    except IndexError:
        try:
            game_box = stat_groups[4]
        except IndexError:
            # edge cases...
            # we can't really extract any more stats
            # so we do an early return
            return {}

    # Calculate the wins, losses, and win rate.
    try:
        wins = int(
            game_box.xpath(".//text()[. = 'Games Won']/../..")[0]
            [1].text.replace(",", ""))
    except IndexError:
        # weird edge case
        wins = 0
    g = game_box.xpath(".//text()[. = 'Games Played']/../..")
    if len(g) < 1:
        # Blizzard f****d up, temporary quick fix for #70
        games, losses = None, None
    else:
        games = int(g[0][1].text.replace(",", ""))

    if mode == "competitive":
        try:
            misc_box = stat_groups[7]
            losses = int(
                misc_box.xpath(".//text()[. = 'Games Lost']/../..")[0]
                [1].text.replace(",", ""))
            ties = int(
                misc_box.xpath(".//text()[. = 'Games Tied']/../..")[0]
                [1].text.replace(",", ""))
        except IndexError:
            # Sometimes the losses and ties don't exist.
            # I'm not 100% as to what causes this, but it might be because there are no ties.
            # In this case, just set ties to 0, and calculate losses manually.
            ties = 0
            # Quickplay shit.
            # Goddamnit blizzard.
            if games is None:
                losses = 0
                games = 0
                wins = 0
            else:
                # Competitive stats do have these values (for now...)
                losses = games - wins

        if games == 0 or games == ties:
            wr = 0
        else:
            wr = round((wins / (games - ties)) * 100, 2)

        built_dict["overall_stats"]["ties"] = ties
        built_dict["overall_stats"]["games"] = games
        built_dict["overall_stats"]["losses"] = losses
        built_dict["overall_stats"]["win_rate"] = wr

    # Update the dictionary.
    built_dict["overall_stats"]["wins"] = wins

    # Build a dict using the stats.
    game_stats = {}
    average_stats = {}
    rolling_average_stats = {}

    for subbox in stat_groups:
        trs = subbox.findall(".//tbody/tr")
        # Update the dict with [0]: [1]
        for subval in trs:
            name, value = util.sanitize_string(subval[0].text), subval[1].text
            # Try and parse out the value. It might be a time!
            # If so, try and extract the time.
            nvl = util.try_extract(value)

            if 'average' in name.lower():
                average_stats[name.replace("_average", "_avg")] = nvl
            elif '_avg_per_10_min' in name.lower():
                # 2017-08-03 - calculate rolling averages.
                name = name.lower().replace("_avg_per_10_min", "")
                rolling_average_stats[name] = nvl
            else:
                game_stats[name] = nvl

    # Manually add the KPD.
    try:
        game_stats["kpd"] = round(
            game_stats["eliminations"] / game_stats["deaths"], 2)
    except KeyError:
        # They don't have any eliminations/deaths.
        # Set the KPD to 0.0.
        # See: #106
        game_stats["kpd"] = 0

    built_dict["game_stats"] = game_stats
    built_dict["average_stats"] = average_stats
    built_dict["rolling_average_stats"] = rolling_average_stats
    built_dict["competitive"] = mode == "competitive"

    if "games" not in built_dict["overall_stats"]:
        # manually calculate it
        # 2017-07-04 - changed to use eliminations
        # since damage done gave a bit of a stupid amount
        # 2017-07-11 - changed to cycle some averages
        average_keys = ("eliminations", "healing_done", "final_blows",
                        "objective_kills")
        for key in average_keys:
            try:
                total = built_dict["game_stats"][key]
                avg = built_dict["average_stats"][key + "_avg"]
            except KeyError:
                continue
            else:
                got = True
                break
        else:
            got = False

        if got:
            games = int(total // avg)

            losses = games - built_dict["overall_stats"]["wins"]
            built_dict["overall_stats"]["games"] = games
            built_dict["overall_stats"]["losses"] = losses
            built_dict["overall_stats"]["win_rate"] = round(
                (built_dict["overall_stats"]["wins"] / games) * 100, 2)
        else:
            # lol make them up
            built_dict["overall_stats"]["games"] = 0
            built_dict["overall_stats"]["losses"] = 0
            built_dict["overall_stats"]["win_rate"] = 0

    return built_dict
Beispiel #6
0
async def bl_get_compstats(ctx: HTTPRequestContext, battletag: str):
    """
    Get stats for a user using the Blizzard sources.
    """
    data = await bz.region_helper(ctx, battletag, region=ctx.request.values.get("region", None))
    if data == (None, None):
        raise HTTPException(404)

    parsed, region = data

    # Start the dict.
    built_dict = {"region": region, "battletag": battletag, "game_stats": [], "overall_stats": {}, "average_stats": []}

    # Get the prestige.
    prestige = parsed.xpath(".//div[@class='player-level']")[0]
    # Extract the background-image from the styles.
    try:
        bg_image = [x for x in prestige.values() if 'background-image' in x][0]
    except IndexError:
        # Cannot find background-image.
        # Yikes!
        # Don't set a prestige.
        built_dict["overall_stats"]["prestige"] = 0
    else:
        for key, val in PRESTIGE.items():
            if key in bg_image:
                prestige_num = val
                break
        else:
            # Unknown.
            prestige_num = None
        built_dict["overall_stats"]["prestige"] = prestige_num

    # Parse out the HTML.
    level = int(parsed.findall(".//div[@class='player-level']/div")[0].text)
    built_dict["overall_stats"]["level"] = level

    hasrank = parsed.findall(".//div[@class='competitive-rank']/div")
    if hasrank:
        comprank = int(hasrank[0].text)
    else:
        comprank = None
    built_dict["overall_stats"]["comprank"] = comprank
    
    # Fetch Avatar
    built_dict["overall_stats"]["avatar"] = parsed.find(".//img[@class='player-portrait']").attrib['src']

    hascompstats = parsed.xpath(".//div[@data-group-id='stats' and @data-category-id='0x02E00000FFFFFFFF']")
    if len(hascompstats) != 2:
        return {"error": 404, "msg": "competitive stats not found", "region": region}, 404
    stat_groups = hascompstats[1]

    # Highlight specific stat groups.
    death_box = stat_groups[4]
    game_box = stat_groups[6]

    # Calculate the wins, losses, and win rate.
    wins = int(game_box.xpath(".//text()[. = 'Games Won']/../..")[0][1].text.replace(",", ""))
    g = game_box.xpath(".//text()[. = 'Games Played']/../..")
    games = int(g[0][1].text.replace(",", ""))
    losses = games - wins
    wr = floor((wins / games) * 100)

    # Update the dictionary.
    built_dict["overall_stats"]["games"] = games
    built_dict["overall_stats"]["losses"] = losses
    built_dict["overall_stats"]["wins"] = wins
    built_dict["overall_stats"]["win_rate"] = wr

    #built_dict["overall_stats"]["rank"] = None  # We don't have a rank in Blizz data.
    #since it always returns Null, this should be disabled for now

    # Build a dict using the stats.
    _t_d = {}
    _a_d = {}
    for subbox in stat_groups:
        trs = subbox.findall(".//tbody/tr")
        # Update the dict with [0]: [1]
        for subval in trs:
            name, value = subval[0].text.lower().replace(" ", "_").replace("_-_", "_"), subval[1].text
            nvl = util.try_extract(value)
            if 'average' in name.lower():
                _a_d[name.replace("_average", "_avg")] = nvl
            else:
                _t_d[name] = nvl

    # Manually add the KPD.
    _t_d["kpd"] = round(_t_d["eliminations"] / _t_d["deaths"], 2)

    built_dict["game_stats"] = _t_d
    built_dict["average_stats"] = _a_d

    return built_dict
Beispiel #7
0
def bl_parse_stats(parsed, mode="quickplay"):
    # Start the dict.
    built_dict = {"game_stats": [], "overall_stats": {}, "average_stats": []}

    # Get the prestige.
    prestige = parsed.xpath(".//div[@class='player-level']")[0]
    # Extract the background-image from the styles.
    try:
        bg_image = [x for x in prestige.values() if 'background-image' in x][0]
    except IndexError:
        # Cannot find background-image.
        # Yikes!
        # Don't set a prestige.
        built_dict["overall_stats"]["prestige"] = 0
    else:
        for key, val in PRESTIGE.items():
            if key in bg_image:
                prestige_num = val
                break
        else:
            # Unknown.
            prestige_num = None
        built_dict["overall_stats"]["prestige"] = prestige_num

    # Parse out the HTML.
    level = int(parsed.findall(".//div[@class='player-level']/div")[0].text)
    built_dict["overall_stats"]["level"] = level

    hasrank = parsed.findall(".//div[@class='competitive-rank']/div")
    if hasrank:
        comprank = int(hasrank[0].text)
    else:
        comprank = None
    built_dict["overall_stats"]["comprank"] = comprank

    # Fetch Avatar
    built_dict["overall_stats"]["avatar"] = parsed.find(".//img[@class='player-portrait']").attrib['src']

    if mode == "competitive":
        hascompstats = parsed.xpath(".//div[@data-group-id='stats' and @data-category-id='0x02E00000FFFFFFFF']")
        if len(hascompstats) != 2:
            return {}
        stat_groups = hascompstats[1]
    elif mode == "quickplay":
        try:
            stat_groups = parsed.xpath(".//div[@data-group-id='stats' and @data-category-id='0x02E00000FFFFFFFF']")[0]
        except IndexError:
            # User has no stats...
            return {}
    else:
        # how else to handle fallthrough case?
        stat_groups = parsed.xpath(".//div[@data-group-id='stats' and @data-category-id='0x02E00000FFFFFFFF']")[0]

    # Highlight specific stat groups.
    try:
        game_box = stat_groups[6]
    except IndexError:
        try:
            game_box = stat_groups[5]
        except IndexError:
            # edge cases...
            # we can't really extract any more stats
            # so we do an early return
            return {}

    # Calculate the wins, losses, and win rate.
    try:
        wins = int(game_box.xpath(".//text()[. = 'Games Won']/../..")[0][1].text.replace(",", ""))
    except IndexError:
        # weird edge case
        wins = 0
    g = game_box.xpath(".//text()[. = 'Games Played']/../..")
    if len(g) < 1:
        # Blizzard f****d up, temporary quick fix for #70
        games, losses = None, None
    else:
        games = int(g[0][1].text.replace(",", ""))

    if mode == "competitive":
        try:
            misc_box = stat_groups[7]
            losses = int(misc_box.xpath(".//text()[. = 'Games Lost']/../..")[0][1].text.replace(",", ""))
            ties = int(misc_box.xpath(".//text()[. = 'Games Tied']/../..")[0][1].text.replace(",", ""))
        except IndexError:
            # Sometimes the losses and ties don't exist.
            # I'm not 100% as to what causes this, but it might be because there are no ties.
            # In this case, just set ties to 0, and calculate losses manually.
            ties = 0
            # Quickplay shit.
            # Goddamnit blizzard.
            if games is None:
                losses = 0
                games = 0
                wins = 0
            else:
                # Competitive stats do have these values (for now...)
                losses = games - wins

        if games == 0 or games == ties:
            wr = 0
        else:
            wr = floor((wins / (games - ties)) * 100)

        built_dict["overall_stats"]["ties"] = ties
        built_dict["overall_stats"]["games"] = games
        built_dict["overall_stats"]["losses"] = losses
        built_dict["overall_stats"]["win_rate"] = wr

    # Update the dictionary.
    built_dict["overall_stats"]["wins"] = wins

    # Build a dict using the stats.
    _t_d = {}
    _a_d = {}
    for subbox in stat_groups:
        trs = subbox.findall(".//tbody/tr")
        # Update the dict with [0]: [1]
        for subval in trs:
            name, value = util.sanitize_string(subval[0].text), subval[1].text
            # Try and parse out the value. It might be a time!
            # If so, try and extract the time.
            nvl = util.try_extract(value)
            if 'average' in name.lower():
                _a_d[name.replace("_average", "_avg")] = nvl
            else:
                _t_d[name] = nvl

    # Manually add the KPD.
    try:
        _t_d["kpd"] = round(_t_d["eliminations"] / _t_d["deaths"], 2)
    except KeyError:
        # They don't have any eliminations/deaths.
        # Set the KPD to 0.0.
        # See: #106
        _t_d["kpd"] = 0

    built_dict["game_stats"] = _t_d
    built_dict["average_stats"] = _a_d
    built_dict["competitive"] = mode == "competitive"

    return built_dict