"""Определение количества страниц в пагинации XenForo. Работает ТОЛЬКО внутри div.pageNav — не ловит числа из аватаров, текста постов, путей к файлам (например /avatars/m/32/32165.jpg). """ import re, logging from bs4 import BeautifulSoup log = logging.getLogger(__name__) def count(soup: BeautifulSoup) -> int: """Сколько страниц. Если пагинации нет — 1. Принцип:
ВСЕ номера страниц видны на любой странице. Кнопки не трогаем — ищем только . """ nav = soup.select_one("div.pageNav") if not nav: return 1 nums = set() for a in nav.select("a"): href = a.get("href", "") text = a.text.strip() # page-N из href m = re.search(r"page-(\d+)", href) if m: nums.add(int(m.group(1))) # текущая страница: число без page-N в href try: nums.add(int(text)) except ValueError: pass # "…", "Назад", "Вперёд" return max(nums) if nums else 1 def verify_last(section_url: str, claimed: int, session) -> int: """HEAD-запросами проверяет реальную последнюю страницу. Если сайт показывает 218, но page-218 → 404 (админ потёр часть тем, пагинацию не пересчитали) — бинарным поиском находит реальную границу. """ if claimed <= 1: return claimed try: import requests r = session.head(f"{section_url}page-{claimed}", timeout=(10, 30), allow_redirects=True) if r.status_code < 400: return claimed # Бинарный поиск lo, hi = 1, claimed while lo < hi: mid = (lo + hi + 1) // 2 hr = session.head(f"{section_url}page-{mid}", timeout=(10, 30), allow_redirects=True) if hr.status_code >= 400: hi = mid - 1 else: lo = mid log.warning(f" Пагинация врала: {claimed} → реально {lo}") return lo except Exception: return claimed # не смогли — верим сайту