diff --git a/app/services/players/profile.py b/app/services/players/profile.py index 50a0e34..eff0565 100644 --- a/app/services/players/profile.py +++ b/app/services/players/profile.py @@ -3,7 +3,7 @@ from app.services.base import TransfermarktBase from app.utils.regex import REGEX_DOB_AGE -from app.utils.utils import clean_response, extract_from_url, safe_regex +from app.utils.utils import clean_response, extract_from_url, safe_regex, trim from app.utils.xpath import Players @@ -28,6 +28,29 @@ def __post_init__(self) -> None: self.page = self.request_url_page() self.raise_exception_if_not_found(xpath=Players.Profile.URL) + def __parse_player_relatives(self) -> list: + """ + Parse the list of related players or trainers from the 'Further information' section on the player page + Returns: + list: A list of dictionaries, each containing ID, profile URL, name, and profile type + """ + relatives = self.page.xpath(Players.Profile.RELATIVES) + + result = [] + for relative in relatives: + url = trim(relative.xpath(Players.Profile.RELATIVE_URL)) + name = trim(relative.xpath(Players.Profile.RELATIVE_NAME)) + result.append( + { + "id": extract_from_url(url), + "url": url, + "name": name, + "profileType": "player" if "spieler" in url else "trainer", + } + ) + + return result + def get_player_profile(self) -> dict: """ Retrieve and parse the player's profile information, including their personal details, @@ -85,6 +108,12 @@ def get_player_profile(self) -> dict: } self.response["outfitter"] = self.get_text_by_xpath(Players.Profile.OUTFITTER) self.response["socialMedia"] = self.get_list_by_xpath(Players.Profile.SOCIAL_MEDIA) + self.response["trainerProfile"] = { + "id": extract_from_url(self.get_text_by_xpath(Players.Profile.TRAINER_PROFILE_URL)), + "url": self.get_text_by_xpath(Players.Profile.TRAINER_PROFILE_URL), + "position": self.get_text_by_xpath(Players.Profile.TRAINER_PROFILE_POSITION), + } + self.response["relatives"] = self.__parse_player_relatives() self.response["updatedAt"] = datetime.now() return clean_response(self.response) diff --git a/app/utils/xpath.py b/app/utils/xpath.py index 6adde93..c7a7686 100644 --- a/app/utils/xpath.py +++ b/app/utils/xpath.py @@ -46,7 +46,15 @@ class Profile: AGENT_NAME = "//span[text()='Player agent:']//following::span[1]//text()" AGENT_URL = "//span[text()='Player agent:']//following::span[1]//a//@href" OUTFITTER = "//span[contains(text(),'Outfitter:')]//following::span[1]//text()" - SOCIAL_MEDIA = "//div[@class='socialmedia-icons']//@href" + SOCIAL_MEDIA = "//div[@class='social-media-toolbar__icons']//@href" + TRAINER_PROFILE_URL = "//a[@class='data-header__box--link']//@href" + TRAINER_PROFILE_POSITION = "//div[@class='dataProfileDaten']//span[1]//text()" + RELATIVES = ( + "//div[@class='box tm-player-additional-data']" + "//a[contains(@href, 'profil/spieler') or contains(@href, 'profil/trainer')]" + ) + RELATIVE_URL = ".//@href" + RELATIVE_NAME = ".//text()" class Search: FOUND = "//text()" diff --git a/tests/players/test_players_profile.py b/tests/players/test_players_profile.py index e2c6cc6..910fbb4 100644 --- a/tests/players/test_players_profile.py +++ b/tests/players/test_players_profile.py @@ -51,6 +51,14 @@ def test_get_player_profile_28003(len_greater_than_0): }, "outfitter": And(str, len_greater_than_0), "socialMedia": And(list, len_greater_than_0), + "relatives": [ + { + "id": And(str, len_greater_than_0), + "url": And(str, len_greater_than_0), + "name": And(str, len_greater_than_0), + "profileType": And(str, len_greater_than_0), + } + ], "updatedAt": datetime, }, ) @@ -181,12 +189,26 @@ def test_get_player_profile_3373(len_greater_than_0): "foot": And(str, len_greater_than_0), "club": { "name": And(str, len_greater_than_0), + "joined": And(str, len_greater_than_0), "lastClubID": And(str, len_greater_than_0), "lastClubName": And(str, len_greater_than_0), "mostGamesFor": And(str, len_greater_than_0), }, "outfitter": And(str, len_greater_than_0), "socialMedia": And(list, len_greater_than_0), + "trainerProfile": { + "id": And(str, len_greater_than_0), + "url": And(str, len_greater_than_0), + "position": And(str, len_greater_than_0), + }, + "relatives": [ + { + "id": And(str, len_greater_than_0), + "url": And(str, len_greater_than_0), + "name": And(str, len_greater_than_0), + "profileType": And(str, len_greater_than_0), + } + ], "updatedAt": datetime, }, )