def _parse_deaths_tibiadata(self, deaths): for death in deaths: level = death["level"] death_time = parse_tibiadata_datetime(death["date"]) m = death_reason.search(death["reason"]) _death = Death(self.name, level, time=death_time) killers_str = [] assists_str = [] involved = [i["name"] for i in death["involved"]] if m and m.group("killers"): killers_str = [ k.strip() for k in split_list(m.group("killers").strip()) ] if m and m.group("assists"): assists_str = [ a.strip() for a in split_list(m.group("assists").strip()) ] for killer in killers_str: summoner = next((i for i in involved if "of %s" % i in killer), None) summon = None if summoner: summon = killer.replace(" of %s" % summoner, "") killer = summoner _death.killers.append( Killer(killer, killer in involved, summon=summon)) for assist in assists_str: _death.assists.append(Killer(assist, assist in involved)) self.deaths.append(_death)
def _parse_tournament_info(self, table): """Parses the tournament info table. Parameters ---------- table: :class:`bs4.BeautifulSoup` The parsed table containing the tournament's information. """ rows = table.find_all('tr') date_fields = ("start_date", "end_date") list_fields = ("worlds",) 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", " ") if field in date_fields: value = parse_tibia_datetime(value) if field in list_fields: value = split_list(value, ",", ",") if field == "phase": value = try_enum(TournamentPhase, value) try: setattr(self, field, value) except AttributeError: pass
def _parse_deaths(self, rows): """ Parses the character's recent deaths Parameters ---------- rows: :class:`list` of :class:`bs4.Tag` A list of all rows contained in the table. """ for row in rows: cols = row.find_all('td') if len(cols) != 2: self.deaths_truncated = True break death_time_str = cols[0].text.replace("\xa0", " ").strip() death_time = parse_tibia_datetime(death_time_str) death = str(cols[1]) death_info = death_regexp.search(death) if death_info: level = int(death_info.group("level")) killers_desc = death_info.group("killers") else: continue death = Death(self.name, level, time=death_time) assists_name_list = [] # Check if the killers list contains assists assist_match = death_assisted.search(killers_desc) if assist_match: # Filter out assists killers_desc = assist_match.group("killers") # Split assists into a list. assists_desc = assist_match.group("assists") assists_name_list = link_search.findall(assists_desc) killers_name_list = split_list(killers_desc) for killer in killers_name_list: killer = killer.replace("\xa0", " ") killer_dict = self._parse_killer(killer) death.killers.append(Killer(**killer_dict)) for assist in assists_name_list: # Extract names from character links in assists list. assist_dict = { "name": link_content.search(assist).group(1), "player": True } death.assists.append(Killer(**assist_dict)) try: self.deaths.append(death) except ValueError: # Some pvp deaths have no level, so they are raising a ValueError, they will be ignored for now. continue
def from_content(cls, content): """Creates an instance of the class from the html content of the thread's page. Parameters ---------- content: :class:`str` The HTML content of the page. Returns ------- :class:`ForumThread` The thread contained in the page, or None if the thread doesn't exist Raises ------ InvalidContent If content is not the HTML of a thread's page. """ parsed_content = parse_tibiacom_content(content) tables = parsed_content.find_all("table") root_tables = [t for t in tables if "BoxContent" in t.parent.attrs.get("class", [])] if not root_tables: error_table = parsed_content.find("table", attrs={"class": "Table1"}) if error_table and "not found" in error_table.text: return None raise errors.InvalidContent("content is not a Tibia.com forum thread.") try: if len(root_tables) == 4: forum_info_table, title_table, posts_table, footer_table = root_tables else: forum_info_table, title_table, footer_table = root_tables posts_table = None except ValueError as e: raise errors.InvalidContent("content is not a Tibia.com forum thread.", e) header_text = forum_info_table.text section, board, *_ = split_list(header_text, "|", "|") thread = cls(section=section, board=board) thread.title = title_table.text.strip() golden_frame = title_table.find("div", attrs={"class": "CipPost"}) thread.golden_frame = golden_frame is not None timezone = timezone_regex.search(footer_table.text).group(1) time_page_column, navigation_column = footer_table.find_all("td", attrs={"class", "ff_white"}) page_links = time_page_column.find_all("a") if page_links: last_link = page_links[-1]["href"] thread.page = int(footer_table.find("span").text) thread.total_pages = max(int(page_number_regex.search(last_link).group(1)), thread.page) navigation_links = navigation_column.find_all("a") if len(navigation_links) == 2: prev_link, next_link = navigation_links prev_link_url = prev_link["href"] thread.previous_topic_number = int(thread_id_regex.search(prev_link_url).group(1)) next_link_url = next_link["href"] thread.next_topic_number = int(thread_id_regex.search(next_link_url).group(1)) elif "Previous" in navigation_links[0].text: prev_link_url = navigation_links[0]["href"] thread.previous_topic_number = int(thread_id_regex.search(prev_link_url).group(1)) else: next_link_url = navigation_links[0]["href"] thread.next_topic_number = int(thread_id_regex.search(next_link_url).group(1)) offset = 1 if timezone == "CES" else 2 if posts_table: thread_info_table, *post_tables = posts_table.find_all("div", attrs={"class": "ForumPost"}) inner_info_table = thread_info_table.find("table") thread_num_col, thread_pages_col, thread_navigation_col = inner_info_table.find_all("td") thread.thread_id = int(thread_num_col.text.replace("Thread #", "")) for post_table in post_tables: post = cls._parse_post_table(post_table, offset) thread.posts.append(post) return thread
def from_content(cls, content): """Parses the board's HTML content from Tibia.com. Parameters ---------- content: :class:`str` The HTML content of the board. Returns ------- :class:`ForumBoard` The forum board contained. Raises ------ InvalidContent` Content is not a board in Tibia.com """ parsed_content = parse_tibiacom_content(content) tables = parsed_content.find_all("table") try: header_table, time_selector_table, threads_table, timezone_table, boardjump_table, *_ = tables except ValueError as e: raise errors.InvalidContent("content is not a forum board", e) header_text = header_table.text.strip() section, name = split_list(header_text, "|", "|") board = cls(name=name, section=section) thread_rows = threads_table.find_all("tr") age_selector = time_selector_table.find("select") if not age_selector: return cls(section=section, name=name) selected_age = age_selector.find("option", {"selected": True}) if selected_age: board.age = int(selected_age["value"]) board_selector = boardjump_table.find("select") selected_board = board_selector.find("option", {"selected": True}) board.board_id = int(selected_board["value"]) page_info = threads_table.find("td", attrs={"class": "ff_info"}) if page_info: current_page_text = page_info.find("span") page_links = page_info.find_all("a") if current_page_text: board.page = int(current_page_text.text) board.total_pages = max(board.page, int(page_number_regex.search(page_links[-1]["href"]).group(1))) for thread_row in thread_rows[1:]: columns = thread_row.find_all("td") if len(columns) != 7: continue entry = cls._parse_thread_row(columns) if isinstance(entry, ListedThread): board.threads.append(entry) cip_border = thread_row.find("div", attrs={"class": "CipBorder"}) if cip_border: entry.golden_frame = True elif isinstance(entry, ListedAnnouncement): board.announcements.append(entry) return board