Exemplo n.º 1
0
    def _parse_world_info(self, world_info_table):
        """
        Parses the World Information table from Tibia.com and adds the found values to the object.

        Parameters
        ----------
        world_info_table: :class:`list`[:class:`bs4.Tag`]
        """
        world_info = {}
        for row in world_info_table:
            cols_raw = row.find_all('td')
            cols = [ele.text.strip() for ele in cols_raw]
            field, value = cols
            field = field.replace("\xa0",
                                  "_").replace(" ", "_").replace(":",
                                                                 "").lower()
            value = value.replace("\xa0", " ")
            world_info[field] = value
        try:
            self.online_count = parse_integer(world_info.pop("players_online"))
        except KeyError:
            self.online_count = 0
        self.location = try_enum(WorldLocation, world_info.pop("location"))
        self.pvp_type = try_enum(PvpType, world_info.pop("pvp_type"))
        self.transfer_type = try_enum(TransferType,
                                      world_info.pop("transfer_type", None),
                                      TransferType.REGULAR)
        m = record_regexp.match(world_info.pop("online_record"))
        if m:
            self.record_count = parse_integer(m.group("count"))
            self.record_date = parse_tibia_datetime(m.group("date"))
        if "world_quest_titles" in world_info:
            self.world_quest_titles = [
                q.strip()
                for q in world_info.pop("world_quest_titles").split(",")
            ]
        if self.world_quest_titles and "currently has no title" in self.world_quest_titles[
                0]:
            self.world_quest_titles = []
        self.experimental = world_info.pop("game_world_type",
                                           None) == "Experimental"
        self.tournament_world_type = try_enum(
            TournamentWorldType, world_info.pop("tournament_world_type", None))
        self._parse_battleye_status(world_info.pop("battleye_status"))
        self.premium_only = "premium_type" in world_info

        month, year = world_info.pop("creation_date").split("/")
        month = int(month)
        year = int(year)
        if year > 90:
            year += 1900
        else:
            year += 2000
        self.creation_date = "%d-%02d" % (year, month)

        for k, v in world_info.items():
            try:
                setattr(self, k, v)
            except AttributeError:
                pass
Exemplo n.º 2
0
    def _parse_rewards_column(cls, column, entry):
        """Parses a column from the tournament's reward section.

        Parameters
        ----------
        column: :class:`bs4.BeautifulSoup`
            The parsed content of the column.
        entry: :class:`RewardEntry`
            The reward entry where the data will be stored to.
        """
        col_str = str(column)
        img = column.find('img')
        if img and "tibiacoin" in img["src"]:
            entry.tibia_coins = parse_integer(column.text)
        if img and "tournamentcoin" in img["src"]:
            entry.tournament_coins = parse_integer(column.text)
        if img and "tournamentvoucher" in img["src"]:
            entry.tournament_ticker_voucher = parse_integer(column.text)
        if img and "trophy" in img["src"]:
            m = CUP_PATTERN.search(col_str)
            if m:
                entry.cup = m.group(1)
            m = DEED_PATTERN.search(col_str)
            if m:
                entry.deed = m.group(1)
        if img and "reward" in img["src"]:
            span = column.find('span', attrs={"class": "HelperDivIndicator"})
            mouse_over = span["onmouseover"]
            title, popup = parse_popup(mouse_over)
            label = popup.find('div', attrs={'class': 'ItemOverLabel'})
            entry.other_rewards = label.text.strip()
Exemplo n.º 3
0
    def _parse_worlds(self, world_rows, tournament=False):
        """Parse the world columns and adds the results to :py:attr:`worlds`.

        Parameters
        ----------
        world_rows: :class:`list` of :class:`bs4.Tag`
            A list containing the rows of each world.
        tournament: :class:`bool`
            Whether these are tournament worlds or not.
        """
        for world_row in world_rows:
            cols = world_row.find_all("td")
            name = cols[0].text.strip()
            status = "Online"
            online = parse_integer(cols[1].text.strip(), None)
            if online is None:
                online = 0
                status = "Offline"
            location = cols[2].text.replace("\u00a0", " ").strip()
            pvp = cols[3].text.strip()

            world = WorldEntry(name, location, pvp, online_count=online, status=status)
            # Check Battleye icon to get information
            battleye_icon = cols[4].find("span", attrs={"class": "HelperDivIndicator"})
            if battleye_icon is not None:
                m = battleye_regexp.search(battleye_icon["onmouseover"])
                if m:
                    world.battleye_date = parse_tibia_full_date(m.group(1))
                    world.battleye_type = BattlEyeType.PROTECTED if world.battleye_date else BattlEyeType.INITIALLY_PROTECTED
            additional_info = cols[5].text.strip()
            world._parse_additional_info(additional_info, tournament)
            self.worlds.append(world)
Exemplo n.º 4
0
    def from_content(cls, content):
        """Parse the content of the World Overview section from Tibia.com into an object of this class.

        Parameters
        ----------
        content: :class:`str`
            The HTML content of the World Overview page in Tibia.com

        Returns
        -------
        :class:`WorldOverview`
            An instance of this class containing all the information.

        Raises
        ------
        InvalidContent
            If the provided content is not the HTML content of the worlds section in Tibia.com
        """
        parsed_content = parse_tibiacom_content(content)
        world_overview = WorldOverview()
        try:
            record_table, *tables \
                = parsed_content.find_all("table", {"class": "TableContent"})
            m = record_regexp.search(record_table.text)
            world_overview.record_count = parse_integer(m.group("count"))
            world_overview.record_date = parse_tibia_datetime(m.group("date"))
            world_overview._parse_worlds_tables(tables)
            return world_overview
        except (AttributeError, KeyError, ValueError) as e:
            raise InvalidContent("content does not belong to the World Overview section in Tibia.com", e)
Exemplo n.º 5
0
    def _parse_leaderboard_entries(self, ranking_table):
        """Parses the leaderboards' entries.

        Parameters
        ----------
        ranking_table: :class:`bs4.BeautifulSoup`
            The table containing the rankings.
        """
        ranking_table_content = ranking_table.find("table", attrs={"class": "TableContent"})
        header, *rows = ranking_table_content.find_all('tr')
        entries = []
        for row in rows:
            raw_columns = row.find_all("td")
            if len(raw_columns) != 4:
                break
            cols = [c.text.strip() for c in raw_columns]
            rank_and_change, character, vocation, score = cols
            m = RANK_PATTERN.search(rank_and_change)
            rank = int(m.group(1))
            change = int(m.group(2))
            voc = try_enum(Vocation, vocation)
            score = parse_integer(score, 0)
            entries.append(LeaderboardEntry(rank=rank, change=change, name=character, vocation=voc, score=score))
        # Results footer
        small = ranking_table.find("small")
        if small:
            pagination_text = small.text
            results_str = RESULTS_PATTERN.search(pagination_text)
            self.results_count = int(results_str.group(1))
        self.entries = entries
Exemplo n.º 6
0
    def _parse_tournament_scores(self, table):
        """Parses the tournament scores table.

        Parameters
        ----------
        table: :class:`bs4.BeautifulSoup`
            The parsed table containing the tournament score set.
        """
        creatures = {}
        rows = table.find_all('tr')
        rules = {}
        for row in rows[1:]:
            cols_raw = row.find_all('td')
            cols = [ele.text.strip() for ele in cols_raw]
            field, value, *_ = cols
            icon = cols_raw[2].find("span")
            field = field.replace("\xa0", "_").replace(" ", "_").replace(":", "").replace("/", "_").lower()
            value = re.sub(r'[^-0-9]', '', value.replace("+/-", ""))
            if not icon:
                creatures[field.replace("_", " ")] = int(value)
            else:
                rules[field] = parse_integer(value)
        if "creature_kills" in rules:
            rules["creature_kills"] = creatures
        self.score_set = ScoreSet(**rules)
Exemplo n.º 7
0
    def _parse_entries_table(self, table):
        """Parse the table containing the highscore entries.

        Parameters
        ----------
        table: :class:`bs4.Tag`
            The table containing the entries.
        """
        entries = table.find_all("tr")
        if entries is None:
            return
        _, header, *rows = entries
        info_row = rows.pop()
        pages_div, results_div = info_row.find_all("div")
        page_links = pages_div.find_all("a")
        listed_pages = [int(p.text) for p in page_links]
        if listed_pages:
            self.page = next((x for x in range(1, listed_pages[-1] + 1) if x not in listed_pages), listed_pages[-1] + 1)
            self.total_pages = max(int(page_links[-1].text), self.page)
        self.results_count = parse_integer(results_pattern.search(results_div.text).group(1))
        for row in rows:
            cols_raw = row.find_all('td')
            if "There is currently no data" in cols_raw[0].text:
                break
            if len(cols_raw) <= 2:
                break
            self._parse_entry(cols_raw)
Exemplo n.º 8
0
    def _parse_filters_table(self, form):
        """
        Parse the filters table found in a highscores page.

        Parameters
        ----------
        form: :class:`bs4.Tag`
            The table containing the filters.
        """
        data = parse_form_data(form, include_options=True)
        self.world = data["world"] if data.get("world") else None
        self.battleye_filter = try_enum(BattlEyeHighscoresFilter, parse_integer(data.get("beprotection"), None))
        self.category = try_enum(Category, parse_integer(data.get("category"), None))
        self.vocation = try_enum(VocationFilter, parse_integer(data.get("profession"), None), VocationFilter.ALL)
        checkboxes = form.find_all("input", {"type": "checkbox", "checked": "checked"})
        values = [int(c["value"]) for c in checkboxes]
        self.pvp_types_filter = [try_enum(PvpTypeFilter, v) for v in values]
        self.available_words = [v for v in data["__options__"]["world"].values() if v]
Exemplo n.º 9
0
    def _parse_spells_table(cls, identifier, spell_table):
        """Parse the table containing spell information.

        Parameters
        ----------
        identifier: :class:`str`
            The identifier of the spell.
        spell_table: :class:`bs4.Tag`
            The table containing the spell information.

        Returns
        -------
        :class:`Spell`
            The spell described in the table.
        """
        attrs = cls._parse_table_attributes(spell_table)
        spell = cls(identifier,
                    attrs["name"],
                    attrs["formula"],
                    premium="yes" in attrs["premium"],
                    exp_level=int(attrs["exp_lvl"]))
        spell.vocations = [s.strip() for s in attrs["vocation"].split(",")]
        spell.cities = [s.strip() for s in attrs["city"].split(",")]
        m = group_pattern.match(attrs["group"])
        groups = m.groupdict()
        spell.group = try_enum(SpellGroup, groups.get("group"))
        spell.group_secondary = groups.get("secondary")
        m = cooldown_pattern.match(attrs["cooldown"])
        cooldowns = m.groupdict()
        spell.cooldown = int(cooldowns["cooldown"])
        spell.cooldown_group = int(cooldowns["group_cooldown"])
        spell.cooldown_group_secondary = parse_integer(
            cooldowns.get("secondary_group_cooldown"), None)
        spell.spell_type = try_enum(SpellType, attrs["type"])
        spell.soul_points = parse_integer(attrs.get("soul_points"), None)
        spell.mana = parse_integer(attrs.get("mana"), None)
        spell.amount = parse_integer(attrs.get("amount"), None)
        spell.price = parse_integer(attrs.get("price"), 0)
        spell.magic_type = attrs.get("magic_type")
        return spell
Exemplo n.º 10
0
    def _parse_rune_table(cls, table):
        """Parse the rune information table.

        Parameters
        ----------
        table: :class:`bs4.Tag`
            The table containing the rune information.

        Returns
        -------
        :class:`Rune`
            The rune described in the table.
        """
        attrs = cls._parse_table_attributes(table)
        rune = Rune(name=attrs["name"],
                    group=try_enum(SpellGroup, attrs["group"]))
        rune.vocations = [v.strip() for v in attrs["vocation"].split(",")]
        rune.magic_type = attrs.get("magic_type")
        rune.magic_level = parse_integer(attrs.get("mag_lvl"), 0)
        rune.exp_level = parse_integer(attrs.get("exp_lvl"), 0)
        rune.mana = parse_integer(attrs.get("mana"), None)
        return rune
Exemplo n.º 11
0
    def _parse_worlds(self, world_rows):
        """Parses the world columns and adds the results to :py:attr:`worlds`.

        Parameters
        ----------
        world_rows: :class:`list` of :class:`bs4.Tag`
            A list containing the rows of each world.
        """
        tournament = False
        for world_row in world_rows:
            cols = world_row.find_all("td")
            name = cols[0].text.strip()
            status = "Online"
            if len(cols) == 1 and name == "Tournament Worlds":
                tournament = True
                continue
            elif len(cols) == 1 and name == "Regular Worlds":
                tournament = False
                continue
            elif name == "World":
                continue
            try:
                online = parse_integer(cols[1].text.strip())
            except ValueError:
                online = 0
                status = "Offline"
            location = cols[2].text.replace("\u00a0", " ").strip()
            pvp = cols[3].text.strip()

            world = ListedWorld(name,
                                location,
                                pvp,
                                online_count=online,
                                status=status)
            # Check Battleye icon to get information
            battleye_icon = cols[4].find("span",
                                         attrs={"class": "HelperDivIndicator"})
            if battleye_icon is not None:
                world.battleye_protected = True
                m = battleye_regexp.search(battleye_icon["onmouseover"])
                if m:
                    world.battleye_date = parse_tibia_full_date(m.group(1))

            additional_info = cols[5].text.strip()
            world._parse_additional_info(additional_info, tournament)
            self.worlds.append(world)
Exemplo n.º 12
0
 def test_parse_integer(self):
     self.assertEqual(1450, parse_integer("1.450"))
     self.assertEqual(1110, parse_integer("1,110"))
     self.assertEqual(15, parse_integer("15"))
     self.assertEqual(0, parse_integer("abc"))
     self.assertEqual(-1, parse_integer("abc", -1))
Exemplo n.º 13
0
    def from_content(cls, content):
        """Parse the content of the spells section.

        Parameters
        -----------
        content: :class:`str`
            The HTML content of the page.

        Returns
        ----------
        :class:`SpellsSection`
            The spells contained and the filtering information.

        Raises
        ------
        InvalidContent
            If content is not the HTML of the spells section.
        """
        try:
            parsed_content = parse_tibiacom_content(content)
            table_content_container = parsed_content.find(
                "div", attrs={"class": "InnerTableContainer"})
            spells_table = table_content_container.find(
                "table", class_=lambda t: t != "TableContent")
            spell_rows = spells_table.find_all(
                "tr", {'bgcolor': ["#D4C0A1", "#F1E0C6"]})
            spells_section = cls()
            for row in spell_rows:
                columns = row.find_all("td")
                if len(columns) != 7:
                    continue
                spell_link = columns[0].find("a")
                url = urllib.parse.urlparse(spell_link["href"])
                query = urllib.parse.parse_qs(url.query)
                cols_text = [c.text for c in columns]
                identifier = query["spell"][0]
                match = spell_name.findall(cols_text[0])
                name, words = match[0]
                group = try_enum(SpellGroup, cols_text[1])
                spell_type = try_enum(SpellType, cols_text[2])
                level = int(cols_text[3])
                mana = parse_integer(cols_text[4], None)
                price = parse_integer(cols_text[5], 0)
                premium = "yes" in cols_text[6]
                spell = SpellEntry(name=name.strip(),
                                   words=words.strip(),
                                   spell_type=spell_type,
                                   level=level,
                                   group=group,
                                   mana=mana,
                                   premium=premium,
                                   price=price,
                                   identifier=identifier)
                spells_section.entries.append(spell)
            form = parsed_content.find("form")
            data = parse_form_data(form)
            spells_section.vocation = try_enum(VocationSpellFilter,
                                               data["vocation"])
            spells_section.group = try_enum(SpellGroup, data["group"])
            spells_section.premium = try_enum(SpellGroup, data["group"])
            spells_section.spell_type = try_enum(SpellType, data["type"])
            spells_section.sort_by = try_enum(SpellSorting, data["sort"])
            spells_section.premium = "yes" in data["premium"] if data[
                "premium"] else None
            return spells_section
        except (AttributeError, TypeError) as e:
            raise errors.InvalidContent(
                "content does not belong to the Spells section", e)