first commit
This commit is contained in:
226
parsers/parser_game.py
Normal file
226
parsers/parser_game.py
Normal file
@@ -0,0 +1,226 @@
|
||||
import requests
|
||||
from bs4 import BeautifulSoup
|
||||
|
||||
from services.game_service import sync_match_page
|
||||
|
||||
BASE_MATCH_URL = "https://wfl.rfs.ru/match/"
|
||||
|
||||
|
||||
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 extract_player_id_from_href(href: str) -> str:
|
||||
if not href:
|
||||
return ""
|
||||
return href.rstrip("/").split("/")[-1].strip()
|
||||
|
||||
|
||||
def detect_captain(item) -> bool:
|
||||
if not item:
|
||||
return False
|
||||
|
||||
text = item.get_text(" ", strip=True).lower()
|
||||
|
||||
return any(x in text for x in ["(к)", "(c)"])
|
||||
|
||||
def parse_starting_teams(soup: BeautifulSoup) -> tuple[list[dict], list[dict]]:
|
||||
home_starting = []
|
||||
away_starting = []
|
||||
|
||||
start_teams = soup.select("div.protocol__block--main div.protocol__unit")
|
||||
if len(start_teams) < 2:
|
||||
return home_starting, away_starting
|
||||
|
||||
def parse_protocol_unit(unit):
|
||||
bench = []
|
||||
|
||||
items = unit.select("ul.protocol__list li.protocol__item")
|
||||
for item in items:
|
||||
link = item.select_one("a.protocol__link")
|
||||
if not link:
|
||||
continue
|
||||
|
||||
href = link.get("href", "")
|
||||
player_id = extract_player_id_from_href(href)
|
||||
|
||||
name_el = link.select_one("div.protocol__name")
|
||||
role_el = link.select_one("div.protocol__role")
|
||||
num_el = item.select_one("span.protocol__number-text")
|
||||
# cap_el = link.select_one("div.protocol__captain")
|
||||
|
||||
bench.append(
|
||||
{
|
||||
"player_external_id": player_id,
|
||||
"player_name": name_el.get_text(strip=True) if name_el else "",
|
||||
"number": num_el.get_text(strip=True) if num_el else "",
|
||||
"position": role_el.get_text(strip=True) if role_el else "",
|
||||
"is_captain": detect_captain(item),
|
||||
}
|
||||
)
|
||||
|
||||
return bench
|
||||
|
||||
home_starting = parse_protocol_unit(start_teams[0])
|
||||
away_starting = parse_protocol_unit(start_teams[1])
|
||||
|
||||
return home_starting, away_starting
|
||||
|
||||
|
||||
def parse_bench(soup: BeautifulSoup) -> tuple[list[dict], list[dict]]:
|
||||
home_bench = []
|
||||
away_bench = []
|
||||
|
||||
units = soup.select("div.protocol__block--additional div.protocol__unit")
|
||||
if len(units) < 2:
|
||||
return home_bench, away_bench
|
||||
|
||||
def parse_protocol_unit(unit):
|
||||
bench = []
|
||||
|
||||
items = unit.select("ul.protocol__list li.protocol__item")
|
||||
for item in items:
|
||||
link = item.select_one("a.protocol__link")
|
||||
if not link:
|
||||
continue
|
||||
|
||||
href = link.get("href", "")
|
||||
player_id = extract_player_id_from_href(href)
|
||||
|
||||
name_el = link.select_one("div.protocol__name")
|
||||
role_el = link.select_one("div.protocol__role")
|
||||
num_el = item.select_one("span.protocol__number-text")
|
||||
# cap_el = link.select_one("div.protocol__captain")
|
||||
|
||||
|
||||
bench.append(
|
||||
{
|
||||
"player_external_id": player_id,
|
||||
"player_name": name_el.get_text(strip=True) if name_el else "",
|
||||
"number": num_el.get_text(strip=True) if num_el else "",
|
||||
"position": role_el.get_text(strip=True) if role_el else "",
|
||||
"is_captain": detect_captain(item),
|
||||
}
|
||||
)
|
||||
|
||||
return bench
|
||||
|
||||
home_bench = parse_protocol_unit(units[0])
|
||||
away_bench = parse_protocol_unit(units[1])
|
||||
|
||||
return home_bench, away_bench
|
||||
|
||||
|
||||
def parse_coaches(soup: BeautifulSoup) -> tuple[list[dict], list[dict]]:
|
||||
home_coaches = []
|
||||
away_coaches = []
|
||||
|
||||
units = soup.select("div.protocol__block--staff div.protocol__unit")
|
||||
if len(units) < 2:
|
||||
return home_coaches, away_coaches
|
||||
|
||||
def parse_staff_unit(unit):
|
||||
coaches = []
|
||||
|
||||
items = unit.select("ul.protocol__list li.protocol__item a.protocol__link")
|
||||
for link in items:
|
||||
href = link.get("href", "")
|
||||
coach_id = extract_player_id_from_href(href)
|
||||
|
||||
name_el = link.select_one("div.protocol__name")
|
||||
role_el = link.select_one("div.protocol__staff-position")
|
||||
|
||||
coaches.append(
|
||||
{
|
||||
"coach_external_id": coach_id,
|
||||
"coach_name": name_el.get_text(strip=True) if name_el else "",
|
||||
"role": role_el.get_text(strip=True) if role_el else "",
|
||||
}
|
||||
)
|
||||
|
||||
return coaches
|
||||
|
||||
home_coaches = parse_staff_unit(units[0])
|
||||
away_coaches = parse_staff_unit(units[1])
|
||||
|
||||
return home_coaches, away_coaches
|
||||
|
||||
|
||||
def parse_referees(soup: BeautifulSoup) -> list[dict]:
|
||||
referees = []
|
||||
|
||||
nodes = soup.select("div.protocol__block--referees div.referee")
|
||||
for node in nodes:
|
||||
role_el = node.select_one("p.referee__position")
|
||||
first_el = node.select_one("span.referee__name")
|
||||
last_el = node.select_one("span.referee__last-name")
|
||||
|
||||
first = first_el.get_text(strip=True) if first_el else ""
|
||||
last = last_el.get_text(strip=True).split("(")[0] if last_el else ""
|
||||
full_name = f"{first} {last}".strip()
|
||||
|
||||
if not full_name:
|
||||
continue
|
||||
|
||||
referees.append(
|
||||
{
|
||||
"referee_name": full_name,
|
||||
"role": (
|
||||
role_el.get_text(strip=True).replace(":", "") if role_el else ""
|
||||
),
|
||||
}
|
||||
)
|
||||
|
||||
return referees
|
||||
|
||||
|
||||
def parse_game_page(html: str) -> dict:
|
||||
soup = BeautifulSoup(html, "html.parser")
|
||||
|
||||
home_starting, away_starting = parse_starting_teams(soup)
|
||||
home_bench, away_bench = parse_bench(soup)
|
||||
home_coaches, away_coaches = parse_coaches(soup)
|
||||
referees = parse_referees(soup)
|
||||
|
||||
return {
|
||||
"home_starting": home_starting,
|
||||
"away_starting": away_starting,
|
||||
"home_bench": home_bench,
|
||||
"away_bench": away_bench,
|
||||
"home_coaches": home_coaches,
|
||||
"away_coaches": away_coaches,
|
||||
"referees": referees,
|
||||
}
|
||||
|
||||
|
||||
def run_parser_game(match_external_id: str) -> None:
|
||||
url = f"{BASE_MATCH_URL}{str(match_external_id).strip()}"
|
||||
html = fetch_html(url)
|
||||
data = parse_game_page(html)
|
||||
|
||||
sync_match_page(
|
||||
match_external_id=str(match_external_id).strip(),
|
||||
home_starting=data["home_starting"],
|
||||
away_starting=data["away_starting"],
|
||||
home_bench=data["home_bench"],
|
||||
away_bench=data["away_bench"],
|
||||
home_coaches=data["home_coaches"],
|
||||
away_coaches=data["away_coaches"],
|
||||
referees=data["referees"],
|
||||
)
|
||||
|
||||
print(
|
||||
f"[parser_game] match={match_external_id} "
|
||||
f"home_starting={len(data['home_starting'])} "
|
||||
f"away_starting={len(data['away_starting'])} "
|
||||
f"home_bench={len(data['home_bench'])} "
|
||||
f"away_bench={len(data['away_bench'])} "
|
||||
f"home_coaches={len(data['home_coaches'])} "
|
||||
f"away_coaches={len(data['away_coaches'])} "
|
||||
f"referees={len(data['referees'])}"
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user