Files
WFL/parsers/parser_players.py

175 lines
6.0 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import requests
from bs4 import BeautifulSoup
from concurrent.futures import ThreadPoolExecutor
from services.players_service import sync_team_roster
URL_TEAMS = "https://wfl.rfs.ru/tournament/1061879/teams"
AMPLUA_FULL = {
"Пз.": "Полузащитник",
"Вр.": "Вратарь",
"Зщ.": "Защитник",
"Нп.": "Нападающий",
"": "",
}
def fetch_html(url: str) -> str:
headers = {"User-Agent": "Mozilla/5.0", "Accept": "*/*"}
r = requests.get(url, headers=headers, timeout=20)
r.raise_for_status()
return r.text
def get_links(html: str) -> list[dict]:
soup = BeautifulSoup(html, "html.parser")
links: list[dict] = []
items = soup.find("ul", class_="teams__list").find_all("li")
for i in items:
href = i.find("a", class_="teams__link").get("href")
team_external_id = href.split("team_id=")[-1].strip()
links.append(
{
"team_external_id": team_external_id,
"url": "https://wfl.rfs.ru" + href,
}
)
return links
def parse_team(html: str) -> dict:
soup = BeautifulSoup(html, "html.parser")
team_el = soup.find("a", class_="team-promo__team-name")
team_name = team_el.get_text(strip=True) if team_el else None
tabs = soup.find("div", class_="tabs__content")
tbody = tabs.find("tbody") if tabs else None
row_players = tbody.find_all("tr", class_="table__row") if tbody else []
coaches_root = soup.find("ul", class_="composition-list")
row_coaches = (
coaches_root.find_all("div", class_="composition-list__item-back")
if coaches_root
else []
)
players = []
for row in row_players:
player_td = row.find("td", class_="table__cell table__cell--player")
player_a = player_td.find("a") if player_td else None
href = player_a.get("href") if player_a else None
player_id = href.split("/")[-1] if href else None
vars_td = row.find_all("td", class_="table__cell table__cell--variable")
games = vars_td[0].get_text(strip=True) if len(vars_td) > 0 else "0"
goals_raw = vars_td[1].get_text(strip=True) if len(vars_td) > 1 else ""
goals_parts = goals_raw.split()
goals = goals_parts[0] if len(goals_parts) > 0 else "0"
penaltys = (
goals_parts[1].replace("(", "").replace(")", "")
if len(goals_parts) > 1
else "0"
)
assists = vars_td[2].get_text(strip=True) if len(vars_td) > 2 else "0"
yellows = vars_td[3].get_text(strip=True) if len(vars_td) > 3 else "0"
reds = vars_td[4].get_text(strip=True) if len(vars_td) > 4 else "0"
number_td = row.find("td", class_="table__cell table__cell--number")
pos_td = row.find(
"td", class_="table__cell table__cell--amplua table__cell--amplua"
)
name_p = row.find("p", class_="table__player-name")
born_td = row.find("td", class_="table__cell table__cell--middle table__cell--birth mobile-hide")
full_player = name_p.get_text(strip=True) if name_p else ""
parts = full_player.split()
players.append(
{
"player_id": player_id or "",
"number": number_td.get_text(strip=True) if number_td else "",
"pos": pos_td.get_text(strip=True) if pos_td else "",
"amplua": AMPLUA_FULL[pos_td.get_text(strip=True) if pos_td else ""],
"player": full_player,
"lastname": parts[0] if len(parts) >= 1 else "",
"name": parts[-1] if len(parts) >= 2 else "",
"born": born_td.get_text(strip=True).split(",")[0] if born_td else "",
"games": games,
"goals": goals,
"penaltys": penaltys,
"assists": assists,
"yellows": yellows,
"reds": reds,
}
)
coaches = []
for coach in row_coaches:
coach_link = coach.find("a", class_="composition-list__player")
href = coach_link.get("href") if coach_link else ""
coach_id = href.split("/")[-1] if href else ""
name = coach.find("span", class_="composition-list__player-first-name")
lastname = coach.find("span", class_="composition-list__player-last-name")
born = coach.find("span", class_="composition-list__player-birth-date")
amplua = coach.find("span", class_="composition-list__player-games-text")
first_name = name.get_text(strip=True) if name else ""
last_name = lastname.get_text(strip=True) if lastname else ""
coaches.append(
{
"coach_id": coach_id,
"name": first_name,
"lastname": last_name,
"player": f"{last_name} {first_name}".strip(),
"born": born.get_text(strip=True).replace(",", "") if born else "",
"amplua": amplua.get_text(strip=True) if amplua else "",
}
)
return {
"team_name": team_name,
"players": players,
"coaches": coaches,
}
def run_parser_players() -> None:
html = fetch_html(URL_TEAMS)
links = get_links(html)
with ThreadPoolExecutor(max_workers=8) as pool:
futures = {pool.submit(fetch_html, item["url"]): item for item in links}
for future, item in futures.items():
try:
html = future.result()
team_data = parse_team(html)
sync_team_roster(
team_external_id=item["team_external_id"],
team_data=team_data,
)
print(
f"[parser_players] team={item['team_external_id']} "
f"players={len(team_data.get('players') or [])} "
f"coaches={len(team_data.get('coaches') or [])}"
)
except Exception as e:
print(f"[parser_players] error team={item['team_external_id']}: {e}")
if __name__ == "__main__":
run_parser_players()