"""Парсинг HTML форума phpBB (subsilver2, нива-лада.рф). Структуры: Список тем в разделе (subsilver2): Заголовок Пост в теме (табличная вёрстка subsilver2): ← строка: автор + дата Автор
Добавлено: 12 авг 2025, 20:00
← строка: аватар + текст ...
текст поста
""" import re import logging from bs4 import BeautifulSoup log = logging.getLogger(__name__) def parse_topics(soup: BeautifulSoup) -> list[dict]: """Распарсить список тем со страницы раздела phpBB. Ищем все a.topictitle → из href вытаскиваем t=ID. Args: soup: BeautifulSoup страницы раздела. Returns: list[dict]: [{id, title, url}]. url может быть None (будет сформирован адаптером). """ items = [] for link in soup.select("a.topictitle"): href = link.get("href", "") # Из href вытаскиваем t=ID match = re.search(r"[?&]t=(\d+)", href) if match is None: continue topic_id = int(match.group(1)) title = link.text.strip() items.append({ "id": topic_id, "title": title, "url": None, # адаптер сформирует сам }) return items def parse_posts(soup: BeautifulSoup) -> list[dict]: """Распарсить посты со страницы темы phpBB (subsilver2). Каждый пост — это 3 в таблице. Ищем b.postauthor как маркер начала поста, затем: - Тот же : дата из "Добавлено:" - Следующий : текст из div.postbody Args: soup: BeautifulSoup страницы темы. Returns: list[dict]: [{author, date, num, text}, ...]. """ posts = [] post_num = 0 for author_tag in soup.select("b.postauthor"): post_num += 1 author = author_tag.text.strip() # ── Дата: ищем "Добавлено:" в том же ─────────────────────── date = "" header_row = author_tag.find_parent("tr") if header_row is not None: date_cell = header_row.select_one("td[width='100%']") if date_cell is not None: date_text = date_cell.get_text(" ", strip=True) date_match = re.search(r"Добавлено:\s*(.+)", date_text) if date_match: date = date_match.group(1).strip() # ── Текст: ищем div.postbody в следующем ─────────────────── text = "" if header_row is not None: body_row = header_row.find_next_sibling("tr") if body_row is not None: body_div = body_row.select_one("div.postbody") if body_div is not None: text = body_div.get_text("\n", strip=True) posts.append({ "author": author, "date": date, "num": f"#{post_num}", "text": text, }) return posts def parse_section_name(soup: BeautifulSoup) -> str | None: """Извлечь название раздела из заголовка phpBB. phpBB обычно показывает название в h2 или в breadcrumbs. Args: soup: BeautifulSoup страницы раздела. Returns: str | None: название раздела. """ # Пробуем h2 (основной заголовок страницы) h2 = soup.select_one("h2") if h2 is not None: text = h2.text.strip() if text: return text # Пробуем title страницы title_tag = soup.select_one("title") if title_tag is not None: text = title_tag.text.strip() # Чистим от названия сайта text = re.sub(r"\s*–\s*.*$", "", text).strip() if text: return text return None