"""Адаптер для форумов на XenForo (vwts.ru). Настройки: data_dir: куда сохранять данные (по умолчанию ./vwts_data). delay: 1.5 сек между запросами. ban_test: 5 быстрых запросов для проверки бана. topics_file: 100 тем на один JSONL-файл. """ from pathlib import Path from ..base import BaseAdapter from . import paginate, parse class XenForoAdapter(BaseAdapter): """Адаптер для форума XenForo (vwts.ru). Использует модули paginate.py и parse.py из этого пакета. """ def __init__(self, data_dir: str | Path = "vwts_data"): """Инициализация. Args: data_dir: Путь к папке с данными (строка или Path). """ self._data_dir = Path(data_dir) # ─── Атрибуты конфигурации ────────────────────────────────────────── @property def data_dir(self) -> Path: return self._data_dir @property def delay(self) -> float: return 1.5 @property def ban_test_count(self) -> int: return 5 @property def topics_per_file(self) -> int: return 100 # ─── Пагинация ────────────────────────────────────────────────────── def count_pages(self, soup) -> int: """Количество страниц в разделе/теме XenForo. Args: soup: BeautifulSoup первой страницы. Returns: int: количество страниц. """ return paginate.count_pages(soup) def page_url(self, section_url: str, page_num: int) -> str: """URL страницы раздела XenForo. Args: section_url: URL раздела (первая страница). page_num: Номер страницы. Returns: str: URL страницы. """ return paginate.page_url(section_url, page_num) def topic_url(self, section_url: str, topic: dict) -> str: """Полный URL темы XenForo. Приоритет: topic['url'] (если есть), иначе формируем из ID. Args: section_url: URL раздела (не используется в XenForo). topic: Словарь темы. Returns: str: полный URL темы. """ if topic.get("url"): return topic["url"] return f"https://vwts.ru/forum/topic/{topic['id']}/" def topic_page_url(self, topic_url: str, page_num: int) -> str: """URL страницы внутри темы XenForo. Args: topic_url: Полный URL темы. page_num: Номер страницы. Returns: str: URL страницы темы. """ return paginate.topic_page_url(topic_url, page_num) # ─── Парсинг ──────────────────────────────────────────────────────── def parse_section_name(self, soup) -> str | None: """Название раздела из h1. Args: soup: BeautifulSoup страницы раздела. Returns: str | None: название раздела. """ return parse.parse_section_name(soup) def parse_topics(self, soup) -> list[dict]: """Список тем со страницы раздела. Args: soup: BeautifulSoup страницы раздела. Returns: list[dict]: [{id, title, url}]. """ return parse.parse_topics(soup) def parse_posts(self, soup) -> list[dict]: """Список постов со страницы темы. Args: soup: BeautifulSoup страницы темы. Returns: list[dict]: [{author, date, num, text}]. """ return parse.parse_posts(soup) def parse_tags(self, soup) -> list[str]: """Теги темы XenForo. Args: soup: BeautifulSoup страницы темы. Returns: list[str]: теги (может быть пусто). """ return parse.parse_tags(soup)