def scorers(self, driver) -> typing.List[Player]: xp = ".//div[@class='tabs__group']" clicks = [(By.ID, "tabitem-top_scorers")] src = selenium_driver.get_html(driver, self.link + "/standings", xp, clicks=clicks) tree = html.fromstring(src) rows = tree.xpath('.//div[@id="table-type-10"]//div[contains(@class,"table__row")]') players = [] for i in rows: items = i.xpath('.//text()') items = [i.strip() for i in items if i.strip()] uri = "".join(i.xpath(".//span[@class='team_name_span']//a/@onclick")).split("'") try: tm_url = "http://www.flashscore.com/" + uri[3] except IndexError: tm_url = "" try: p_url = "http://www.flashscore.com/" + uri[1] except IndexError: p_url = "" rank, name, tm, goals, assists = items country = "".join(i.xpath('.//span[contains(@class,"flag")]/@title')).strip() flag = transfer_tools.get_flag(country) players.append(Player(rank=rank, flag=flag, name=name, link=p_url, team=tm, team_link=tm_url, goals=int(goals), assists=assists)) self.fetch_logo(driver) return players
def player_competitions(self, driver) -> typing.List[str]: xp = './/div[contains(@class, "subTabs")]' src = selenium_driver.get_html(driver, self.link + '/squad', xp) tree = html.fromstring(src) options = tree.xpath(xp + "/div/text()") options = [i.strip() for i in options] return options
def by_link(cls, link, driver=None): src = selenium_driver.get_html(driver, link, xpath=".//div[@class='team spoiler-content']") tree = html.fromstring(src) country = tree.xpath('.//h2[@class="tournament"]/a[2]//text()')[0].strip() league = tree.xpath('.//div[@class="teamHeader__name"]//text()')[0].strip() title = f"{country.upper()}: {league}" return cls(url=link, title=title)
def by_id(cls, comp_id, driver=None): url = "http://flashscore.com/?r=2:" + comp_id src = selenium_driver.get_html(driver, url, xpath=".//div[@class='team spoiler-content']") url = selenium_driver.get_target_page(driver, url) tree = html.fromstring(src) country = tree.xpath('.//h2[@class="tournament"]/a[2]//text()')[0].strip() league = tree.xpath('.//div[@class="teamHeader__name"]//text()')[0].strip() title = f"{country.upper()}: {league}" return cls(url=url, title=title)
def players(self, driver, tab=0) -> typing.List[Player]: xp = './/div[contains(@class,"playerTable")]' src = selenium_driver.get_html(driver, self.link + "/squad", xp) tree = html.fromstring(src) tab += 1 # tab is Indexed at 0 but xpath indexes from [1] rows = tree.xpath(f'.//div[contains(@class, "playerTable")][{tab}]//div[contains(@class,"profileTable__row")]') players = [] position = "" for i in rows: pos = "".join(i.xpath('./text()')).strip() if pos: # The way the data is structured contains a header row with the player's position. try: position = pos.strip('s') except IndexError: position = pos continue # There will not be additional data. name = "".join(i.xpath('.//div[contains(@class,"")]/a/text()')) try: # Name comes in reverse order. player_split = name.split(' ', 1) name = f"{player_split[1]} {player_split[0]}" except IndexError: pass country = "".join(i.xpath('.//span[contains(@class,"flag")]/@title')) flag = transfer_tools.get_flag(country) number = "".join(i.xpath('.//div[@class="tableTeam__squadNumber"]/text()')) try: age, apps, g, y, r = i.xpath( './/div[@class="playerTable__icons playerTable__icons--squad"]//div/text()') except ValueError: age = "".join(i.xpath('.//div[@class="playerTable__icons playerTable__icons--squad"]//div/text()')) apps = g = y = r = 0 injury = "".join(i.xpath('.//span[contains(@class,"absence injury")]/@title')) if injury: injury = f"<:injury:682714608972464187> " + injury # I really shouldn't hard code emojis. link = "".join(i.xpath('.//div[contains(@class,"")]/a/@href')) link = f"http://www.flashscore.com{link}" if link else "" try: number = int(number) except ValueError: number = 00 pl = Player(name=name, number=number, country=country, link=link, position=position, age=age, apps=apps, goals=int(g), yellows=y, reds=r, injury=injury, flag=flag) players.append(pl) return players
def by_id(cls, match_id, driver=None): url = "http://www.flashscore.com/match/" + match_id src = selenium_driver.get_html(driver, url, xpath=".//div[@class='team spoiler-content']") tree = html.fromstring(src) home = "".join(tree.xpath('.//div[contains(@class, "tname-home")]//a/text()')).strip() away = "".join(tree.xpath('.//div[contains(@class, "tname-away")]//a/text()')).strip() ko = "".join(tree.xpath(".//div[@id='utime']/text()")).strip() ko = datetime.datetime.strptime(ko, "%d.%m.%Y %H:%M") country_league = "".join(tree.xpath('.//span[@class="description__country"]//text()')) comp_link_raw = "".join(tree.xpath('.//span[@class="description__country"]//a/@onclick')) country, competition = country_league.split(':') country = country.strip() competition = competition.strip() comp_link = "http://www.flashscore.com" + comp_link_raw.split("'")[1] return cls(url=url, home=home, away=away, time=ko, kickoff=ko, league=competition, comp_link=comp_link, country=country)
def fetch_fixtures(self, driver, subpage) -> typing.List[Fixture]: link = self.link + subpage src = selenium_driver.get_html(driver, link, './/div[@class="sportName soccer"]') # Ugly, but, whatever. try: logo = driver.find_element_by_xpath('.//div[contains(@class,"logo")]') if logo != "none": logo = logo.value_of_css_property('background-image') self.logo_url = logo.strip("url(").strip(")").strip('"') except NoSuchElementException: pass tree = html.fromstring(src) fixture_rows = tree.xpath('.//div[contains(@class,"sportName soccer")]/div') league, country = None, None fixtures = [] for i in fixture_rows: try: fixture_id = i.xpath("./@id")[0].split("_")[-1] url = "http://www.flashscore.com/match/" + fixture_id except IndexError: cls = i.xpath('./@class') # This (might be) a header row. if "event__header" in str(cls): country, league = i.xpath('.//div[contains(@class, "event__title")]//text()') league = league.split(' - ')[0] continue # score try: score_home, score_away = i.xpath('.//div[contains(@class,"event__scores")]/span/text()') except ValueError: score_home, score_away = None, None else: score_home = int(score_home.strip()) score_away = int(score_away.strip()) home, away = i.xpath('.//div[contains(@class,"event__participant")]/text()') time = "".join(i.xpath('.//div[@class="event__time"]//text()')) for x in ["Pen", 'AET', 'FRO', 'WO']: time = time.replace(x, '') if "'" in time: time = f"⚽ LIVE! {time}" elif not time: time = "?" elif "Postp" in time: time = "🚫 Postponed " elif "Awrd" in time: try: time = datetime.datetime.strptime(time.strip('Awrd'), '%d.%m.%Y') except ValueError: time = datetime.datetime.strptime(time.strip('Awrd'), '%d.%m. %H:%M') time = time.strftime("%d/%m/%Y") time = f"{time} 🚫 FF" # Forfeit else: # Should be dd.mm hh:mm or dd.mm.yyyy try: time = datetime.datetime.strptime(time, '%d.%m.%Y') if time.year != datetime.datetime.now().year: time = time.strftime("%d/%m/%Y") except ValueError: dtn = datetime.datetime.now() try: time = datetime.datetime.strptime(f"{dtn.year}.{time}", '%Y.%d.%m. %H:%M') except ValueError: time = datetime.datetime.strptime(f"{dtn.year}.{dtn.day}.{dtn.month}.{time}", '%Y.%d.%m.%H:%M') is_televised = True if i.xpath(".//div[contains(@class,'tv')]") else False fixture = Fixture(time, home.strip(), away.strip(), score_home=score_home, score_away=score_away, is_televised=is_televised, country=country.strip(), league=league.strip(), url=url) fixtures.append(fixture) return fixtures
def refresh(self, driver, for_discord=False): # This is a very intensive, full lookup xp = ".//div[@id='utime']" src = selenium_driver.get_html(driver, self.url, xp) tree = html.fromstring(src) # Some of these will only need updating once per match if self.kickoff is None: ko = "".join(tree.xpath(".//div[@id='utime']/text()")) ko = datetime.datetime.strptime(ko, "%d.%m.%Y %H:%M") self.kickoff = ko if self.referee is None: text = tree.xpath('.//div[@class="content"]//text()') ref = "".join([i for i in text if "referee" in i.lower()]).strip().replace('Referee:', '') venue = "".join([i for i in text if "venue" in i.lower()]).strip().replace('Venue:', '') self.referee = ref self.stadium = venue if self.country is None or self.league is None: country_league = "".join(tree.xpath('.//span[@class="description__country"]//text()')) comp_link_raw = "".join(tree.xpath('.//span[@class="description__country"]//a/@onclick')) country, competition = country_league.split(':') country = country.strip() competition = competition.strip() comp_link = "http://www.flashscore.com" + comp_link_raw.split("'")[1] self.country = country self.league = competition self.comp_link = comp_link if not for_discord: scores = tree.xpath('.//div[@class="current-result"]//span[@class="scoreboard"]/text()') self.score_home = int(scores[0]) self.score_away = int(scores[1]) self.formation = self.get_formation(driver) self.table = self.get_table(driver) event_rows = tree.xpath('.//div[@class="detailMS"]/div') events = [] for i in event_rows: event = MatchEvent() if "Header" in i.attrib['class']: parts = [x.strip() for x in i.xpath('.//text()')] event.type = "header" event.description = " ".join(parts) if "Penalties" in parts: self.penalties_home = parts[1] self.penalties_away = parts[3] else: team = i.attrib['class'] event.team = self.home if "home" in team else self.away for node in i.xpath("./*"): node_type = node.attrib['class'] try: event.description = node.attrib['title'] print(f'Event description found: {event.description}') except KeyError: pass # Check if events actually exist if "empty" in node_type: event.type = "No events in half" continue # Time box if "time-box" in node_type: time = "".join(node.xpath('.//text()')).strip() event.time = time # Event types: Disciplinary elif "y-card" in node_type: event.type = "booking" elif "yr-card" in node_type: event.type = "2yellow" elif "r-card" in node_type: event.type = "dismissal" # Event types: Scoring elif "penalty-missed" in node_type: event.type = "Penalty miss" elif "soccer-ball" in node_type: event.type = "goal" # Event type: Video Assistant Referee Review elif "var" in node_type: event.type = "VAR" event.note = "".join(node.xpath('.//text()')).strip('()') # Event type: Substitution elif node_type == "icon-box substitution-in": event.type = "substitution" elif node_type == "substitution-in-name": event.player_on = ''.join(node.xpath('.//a/text()')).strip() elif node_type == "substitution-out-name": event.player_off = ''.join(node.xpath('.//a/text()')).strip() # Player info elif "participant-name" in node_type: event.player = ''.join(node.xpath('.//text()')).strip() elif "assist" in node_type: event.assist = "".join(node.xpath('.//text()')).strip('()') # Event notes elif any(x in node_type for x in ["subincident-name", "note-name"]): event.note = "".join(node.xpath('.//text()')).strip('()') else: print('Error in match', self.home, "vs", self.away, self.url) print("unhandled node", node_type, team) events.append(event) self.events = events # TODO: Fetching images self.images = tree.xpath('.//div[@class="highlight-photo"]//img/@src')