87 lines
2.6 KiB
Python
87 lines
2.6 KiB
Python
"""Пагинация phpBB.
|
|
|
|
phpBB: пагинация через параметр start=N, где N = (page-1) * items_per_page.
|
|
|
|
На странице раздела:
|
|
<a href="./viewforum.php?f=22&start=25">2</a>
|
|
<a href="./viewforum.php?f=22&start=50">3</a>
|
|
...
|
|
<a href="./viewforum.php?f=22&start=1800">72</a>
|
|
|
|
На странице темы:
|
|
<a href="./viewtopic.php?f=22&t=123&start=10">2</a>
|
|
...
|
|
"""
|
|
|
|
import re, logging
|
|
from bs4 import BeautifulSoup
|
|
|
|
log = logging.getLogger(__name__)
|
|
|
|
|
|
def count(soup: BeautifulSoup) -> int:
|
|
"""Сколько страниц в пагинации. Если нет — 1."""
|
|
for cls in ("pagination", "page-nav"):
|
|
nav = soup.find("ul", class_=cls)
|
|
if nav:
|
|
break
|
|
else:
|
|
return 1
|
|
|
|
nums = set()
|
|
for a in nav.select("a"):
|
|
href = a.get("href", "")
|
|
text = a.text.strip()
|
|
|
|
# start=N из href
|
|
m = re.search(r"[?&]start=(\d+)", href)
|
|
if m:
|
|
per_page = int(m.group(1))
|
|
# Определяем items_per_page по первому start
|
|
if hasattr(count, "_per_page"):
|
|
pass
|
|
nums.add(per_page)
|
|
|
|
# Числовой текст ссылки
|
|
try:
|
|
nums.add(int(text))
|
|
except ValueError:
|
|
pass
|
|
|
|
if not nums:
|
|
return 1
|
|
|
|
# Находим максимальный номер страницы из текста ссылок
|
|
max_page_num = max((int(a.text.strip()) for a in nav.select("a")
|
|
if a.text.strip().isdigit()), default=1)
|
|
|
|
# Находим max start
|
|
max_start = max(nums)
|
|
|
|
# Определяем per_page из наименьшего start > 0
|
|
positive_starts = [s for s in nums if s > 0]
|
|
if positive_starts:
|
|
per_page = min(positive_starts)
|
|
else:
|
|
# Не можем определить — возвращаем по тексту ссылок
|
|
return max_page_num
|
|
|
|
# Вычисляем: страниц = (max_start / per_page) + 1
|
|
pages = (max_start // per_page) + 1
|
|
return pages
|
|
|
|
|
|
def page_url(base_url: str, page: int, per_page: int) -> str:
|
|
"""Сформировать URL для страницы пагинации.
|
|
|
|
Args:
|
|
base_url: URL без start= (напр. viewforum.php?f=22)
|
|
page: номер страницы (1-based)
|
|
per_page: элементов на странице
|
|
"""
|
|
if page <= 1:
|
|
return base_url
|
|
start = (page - 1) * per_page
|
|
sep = "&" if "?" in base_url else "?"
|
|
return f"{base_url}{sep}start={start}"
|