def _parse_current_war_information(cls, text): """Parse the guild's current war information. Parameters ---------- text: :class:`str` The text describing the current war's information. Returns ------- :class:`GuildWarEntry` The guild's war entry for the current war. """ text = text.replace('\xa0', ' ').strip() names_match = war_guilds_regegx.search(text) guild_name, opposing_name = names_match.groups() scores_match = war_score_regex.findall(text) guild_score, opposing_score = scores_match fee_match = war_fee_regex.findall(text) guild_fee, opposing_fee = fee_match score_limit_match = war_score_limit_regex.search(text) score_limit = score_limit_match.group(1) end_date_match = war_end_regex.search(text) end_date_str = end_date_match.group(1) end_date = parse_tibia_date(end_date_str) return GuildWarEntry(guild_name=guild_name, opponent_name=opposing_name, guild_score=int(guild_score), opponent_score=int(opposing_score), guild_fee=int(guild_fee), opponent_fee=int(opposing_fee), score_limit=int(score_limit), end_date=end_date)
def _parse_guild_guildhall(self, info_container): """ Parse the guild's guildhall info. Parameters ---------- info_container: :class:`bs4.Tag` The parsed content of the information container. """ m = guildhall_regex.search(info_container.text) if m: paid_until = parse_tibia_date(m.group("date").replace("\xa0", " ")) self.guildhall = GuildHouse(m.group("name"), self.world, paid_until_date=paid_until)
def _parse_guild_disband_info(self, info_container): """ Parse the guild's disband info, if available. Parameters ---------- info_container: :class:`bs4.Tag` The parsed content of the information container. """ m = disband_regex.search(info_container.text) if m: self.disband_condition = m.group(2) self.disband_date = parse_tibia_date(m.group(1).replace("\xa0", " "))
def _parse_guild_info(self, info_container): """ Parse the guild's general information and applies the found values. Parameters ---------- info_container: :class:`bs4.Tag` The parsed content of the information container. """ m = founded_regex.search(info_container.text) if m: description = m.group("desc").strip() self.description = description if description else None self.world = m.group("world") self.founded = parse_tibia_date(m.group("date").replace("\xa0", " ")) self.active = "currently active" in m.group("status")
def _parse_entry(cls, cols_raw): img = cols_raw[0].find('img') img_url = img["src"] category_name = ICON_PATTERN.search(img_url) category = try_enum(NewsCategory, category_name.group(1)) for br in cols_raw[1].find_all("br"): br.replace_with("\n") date_str, news_type_str = cols_raw[1].text.splitlines() date = parse_tibia_date(date_str) news_type_str = news_type_str.replace('\xa0', ' ') news_type = try_enum(NewsType, news_type_str) title = cols_raw[2].text news_link = cols_raw[2].find('a') url = urllib.parse.urlparse(news_link["href"]) query = urllib.parse.parse_qs(url.query) news_id = int(query["id"][0]) return cls(news_id, title, news_type, category, date, category_icon=img_url)
def test_parse_tibia_date_invalid(self): date = utils.parse_tibia_date(TIBIA_DATETIME_INVALID) self.assertIsNone(date)
def test_parse_tibia_date(self): date = utils.parse_tibia_date(TIBIA_DATE) self.assertIsInstance(date, datetime.date) self.assertEqual(date.month, 6) self.assertEqual(date.day, 20) self.assertEqual(date.year, 2018)
def _parse_war_history_entry(cls, text): """Parses a guild's war information. Parameters ---------- text: :class:`str` The text describing the war's information. Returns ------- :class:`GuildWarEntry` The guild's war entry described in the text.. """ text = text.replace('\xa0', ' ').strip() header_match = war_history_header_regex.search(text) guild_name, opposing_name = header_match.groups() if "disbanded guild" in opposing_name: opposing_name = None start_duration_match = war_start_duration_regex.search(text) start_str, duration_str = start_duration_match.groups() start_date = parse_tibia_date(start_str) duration = datetime.timedelta(days=int(duration_str)) kills_match = kills_needed_regex.search(text) kills_needed = int(kills_match.group(1)) fee_match = war_history_fee_regex.search(text) guild_fee, opponent_fee = fee_match.groups() winner = None surrender = False end_date = None guild_score = opponent_score = 0 surrender_match = surrender_regex.search(text) if surrender_match: surrending_guild = surrender_match.group(1) end_date = parse_tibia_date(surrender_match.group(2)) winner = guild_name if surrending_guild != guild_name else opposing_name surrender = True war_score_match = war_score_regex.findall(text) if war_score_match and len(war_score_match) == 2: guild_score, opponent_score = war_score_match guild_score = int(guild_score) opponent_score = int(guild_score) war_end_match = war_ended_regex.search(text) if war_end_match: end_date = parse_tibia_date(war_end_match.group(1)) winning_guild = war_end_match.group(2) if "disbanded guild" in winning_guild: winning_guild = None winner = guild_name if winning_guild == guild_name else opposing_name loser_score_match = war_score_end_regex.search(text) loser_score = int( loser_score_match.group(1)) if loser_score_match else 0 guild_score = kills_needed if guild_name == winner else loser_score opponent_score = kills_needed if guild_name != winner else loser_score if "no guild had reached the needed kills" in text: winner = guild_name if guild_score > opponent_score else opposing_name entry = GuildWarEntry(guild_name=guild_name, opponent_name=opposing_name, start_date=start_date, duration=duration, score_limit=kills_needed, guild_fee=int(guild_fee), opponent_fee=int(opponent_fee), surrender=surrender, winner=winner, end_date=end_date, opponent_score=opponent_score, guild_score=guild_score) return entry
def _parse_character_information(self, rows): """ Parses the character's basic information and applies the found values. Parameters ---------- rows: :class:`list` of :class:`bs4.Tag` A list of all rows contained in the table. """ int_rows = ["level", "achievement_points"] char = {} houses = [] for row in rows: 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", " ") # This is a special case cause we need to see the link if field == "house": house_text = value paid_until = house_regexp.search(house_text).group(1) paid_until_date = parse_tibia_date(paid_until) house_link = cols_raw[1].find('a') url = urllib.parse.urlparse(house_link["href"]) query = urllib.parse.parse_qs(url.query) houses.append({ "id": int(query["houseid"][0]), "name": house_link.text.strip(), "town": query["town"][0], "paid_until": paid_until_date }) continue if field in int_rows: value = int(value) char[field] = value # If the character is deleted, the information is fouund with the name, so we must clean it m = deleted_regexp.match(char["name"]) if m: char["name"] = m.group(1) char["deletion_date"] = parse_tibia_datetime(m.group(2)) if "guild_membership" in char: m = guild_regexp.match(char["guild_membership"]) char["guild_membership"] = GuildMembership(m.group(2), m.group(1)) if "(traded)" in char["name"]: char["name"] = char["name"].replace("(traded)", "").strip() char["traded"] = True if "former_names" in char: former_names = [ fn.strip() for fn in char["former_names"].split(",") ] char["former_names"] = former_names if "never" in char["last_login"]: char["last_login"] = None else: char["last_login"] = parse_tibia_datetime(char["last_login"]) m = title_regexp.match(char.get("title", "")) if m: name = m.group(1).strip() unlocked = int(m.group(2)) if name == "None": name = None char["title"] = name char["unlocked_titles"] = unlocked char["vocation"] = try_enum(Vocation, char["vocation"]) char["sex"] = try_enum(Sex, char["sex"]) char["account_status"] = try_enum(AccountStatus, char["account_status"]) for k, v in char.items(): try: setattr(self, k, v) except AttributeError: # This means that there is a attribute in the character's information table that does not have a # corresponding class attribute. pass self.houses = [ CharacterHouse(h["id"], h["name"], self.world, h["town"], self.name, h["paid_until"]) for h in houses ]
def from_content(cls, content, news_id=0): """ Gets a news entry by its HTML content from Tibia.com Notes ----- Since there's no way to obtain the entry's Id from the page contents, it will always be 0. A news_id can be passed to set the news_id of the resulting object. Parameters ---------- content: :class:`str` The HTML content of the page. news_id: :class:`int`, optional The news_id belonging to the content being parsed. Returns ------- :class:`News` The news article found in the page. Raises ------ InvalidContent If content is not the HTML of a news' page. """ if "(no news with id " in content: return None try: parsed_content = parse_tibiacom_content(content) # Read Information from the headline headline = parsed_content.find("div", attrs={"class": "NewsHeadline"}) img = headline.find('img') img_url = img["src"] category_name = ICON_PATTERN.search(img_url) category = try_enum(NewsCategory, category_name.group(1)) title_div = headline.find("div", attrs={"class": "NewsHeadlineText"}) title = title_div.text.replace('\xa0', ' ') date_div = headline.find("div", attrs={"class": "NewsHeadlineDate"}) date_str = date_div.text.replace('\xa0', ' ').replace('-', '').strip() date = parse_tibia_date(date_str) # Read the page's content. content_table = parsed_content.find("table") content_row = content_table.find("td") content = content_row.encode_contents().decode() thread_id = None thread_div = content_table.find("div") if thread_div: news_link = thread_div.find('a') url = urllib.parse.urlparse(news_link["href"]) query = urllib.parse.parse_qs(url.query) thread_id = int(query["threadid"][0]) return cls(news_id, title, content, date, category, thread_id=thread_id, category_icon=img_url) except AttributeError: raise InvalidContent( "content is not from the news archive section in Tibia.com")