<file_sep>
This repository contains code to scrape UFC figthers datasets  and stats from ESPN website.
There is also a boiler plate code to generate an UFC fight summary table with [gt](https://gt.rstudio.com/) inspred by  a [Thomas Mock](https://gist.github.com/jthomasmock/4a8851d74d911ce9b90bf7a43c4cdf47) gist post. 

![](Graphics/mcgregor_poirier.png)<file_sep>source("ufc_scraping.R")

# function to combine player name + country
combine_word <- function(name, country){
  glue::glue(
    "<span style='line-height:14px'><span style='font-weight:bold;font-size:16px'>{name}</span></span>
        <span style='line-height:16px'><span style ='font-weight:bold;color:grey;font-size:9px'>{country}</span></span>"
  )
}


# Graphical Table ---------------------------------------------------------
figthers_tab <- function(event_num, weight_class,fighters_stats) {
  fighters_stats %>% 
    mutate(
      combo = combine_word(player_name_ordered,player_country),
      combo = map(combo,gt::html)
    ) %>% 
    select(player_headshot, combo, everything(), -c(player_name_ordered, player_country)) %>% 
    gt() %>% 
    text_transform(
      locations = cells_body(c(player_headshot)),
      fn = function(x) {
        web_image(url =x, 
                  height = px(40)) 
      }
    ) %>% 
    cols_label(
      player_headshot = "",
      combo = "", 
      odds = "Odds",
      nb_wins = "W",
      nb_loses = "L",
      last_5_kds = "KD",
      last_5_body_pct = "%BODY",
      last_5_head_pct = "%HEAD",
      last_5_leg_pct = "%LEG"
    ) %>% 
    tab_spanner(
      label = "Career Record",
      columns = c(nb_wins, nb_loses)
    ) %>% 
    tab_spanner(
      label = "Last 5 fights", 
      columns = 6:9
    ) %>% 
    data_color(
      c(odds),
      colors = scales::col_numeric(
        palette = c("#489bca","white","#ff2d21" ),
        domain = NULL
      ),
      autocolor_text = FALSE
    ) %>% 
    tab_style(
      style = cell_borders(sides = "bottom", color = "transparent", weight = px(3)),
      locations = cells_body(
        columns = 1
      )
    )  %>% 
    tab_style(
      style = cell_borders(sides = "bottom", color = "transparent", weight = px(3)),
      locations = cells_body(
        rows = 2
      )
    ) %>% 
    tab_style(
      style = cell_text(font = "Inconsolata"), 
      locations = cells_body(columns = c(3:9))
    ) %>% 
    tab_style(
      style =  cell_text(weight = "bold"),
      locations = cells_body(columns = c(nb_wins,nb_loses))
    ) %>% 
    fmt_percent(c(last_5_body_pct,last_5_head_pct,last_5_leg_pct), scale_values = FALSE, decimals = 1) %>% 
    tab_header(
      title = html(glue('<b> <img width = 50, style = "vertical-align: middle;" src = "{mma_logo}"/>  UFC {event_num} - {weight_class}</b>'))
    ) %>% 
    tab_source_note(
      html("<span style='float:left';><b>Data</b>: ESPN & Draftkings</span><span style = 'float:right';> <span style= 'font-family:\"Font Awesome 5 Brands\"'>&#xf099;</span>@issa_madjid")
    ) %>% 
    tab_footnote(footnote = "Knockdowns",
                 locations = cells_column_labels(
                   columns = c(last_5_kds)
                 )) %>% 
    tab_footnote(footnote = "Target Breakdown Body",
                 locations = cells_column_labels(
                   columns = c(last_5_body_pct)
                 )) %>% 
    tab_footnote(footnote = "Target Breakdown Head",
                 locations = cells_column_labels(
                   columns = c(last_5_head_pct)
                 )) %>% 
    tab_footnote(footnote = "Target Breakdown Leg",
                 locations = cells_column_labels(
                   columns = c(last_5_leg_pct)
                 )) %>% 
    opt_table_font(font = "Lato") %>% 
    tab_options(
      heading.align = "center",
      heading.border.bottom.width = px(3),
      heading.border.bottom.color = "black",
      table.border.top.width = px(3),
      table.border.top.color =  "transparent",
      table.border.bottom.color =  "transparent",
      table.border.bottom.width =  px(3),
      table.background.color = "#f9fbfc",
      column_labels.font.size = 14,
      table.width = px(600),
      heading.title.font.weight = "bold",
      data_row.padding = px(1),
      source_notes.padding = px(8),
      footnotes.font.size = px(10)
    )
}


fighters_stats <- function(fighter_1, fighter_2, fighter_1_odd, fighter_2_odd) { 
  fighters_dataset %>% 
    filter(player_name %in% c(fighter_1, fighter_2)) %>% 
    mutate(
      odds = c(fighter_1_odd, fighter_2_odd),
      player_name_ordered = str_replace(player_name,"(.+), (.+)","\\2 \\1"),
      player_headshot = glue("https://a.espncdn.com/combiner/i?img=/i/headshots/mma/players/full/{id}.png"),
      summarize = map(map(id, get_fighter_stats), summarise_player_stats)
    ) %>% 
    unnest_wider(summarize) %>% 
    select(player_headshot, player_name_ordered, player_country, odds,nb_wins, nb_loses,contains("5")) 
  
}

# Gather all
event_tab <- function(event_num, weight_class, fighter_1, fighter_2, fighter_1_odd, fighter_2_odd) {
  fighters_stats <- fighters_stats(fighter_1, fighter_2, fighter_1_odd, fighter_2_odd)
  figthers_tab(event_num, weight_class,fighters_stats)
}

# Example
event_tab(261,"Welterweight","<NAME>","<NAME>",+320,-435)

# UFC 264 
mcgregor_poirier <- event_tab(264,"Lightweight","<NAME>","<NAME>",+105,-134)
gtsave(mcgregor_poirier,"mcgregor_poirier.png",path = "Graphics")

burns_thompson <- event_tab(264,"Welterweight","<NAME>","<NAME>",+130,-162)
gtsave(burns_thompson,"burns_thompson.png",path = "Graphics")

makhachev_moises <- event_tab("Fight Night","Lightweight","<NAME>","<NAME>",-720,+500)
gtsave(makhachev_moises,"makhachev_moises.png",path = "Graphics")

reneau_tate <- event_tab("Fight Night","Women's Bantamweight","Reneau, Marion","<NAME>",+120,-140)
gtsave(reneau_tate,"reneau_tate.png",path = "Graphics")
<file_sep>
# Load Libraries ----------------------------------------------------------
library(xml2)
library(rvest)
library(tidyverse)
library(purrr)
library(magick)
library(glue)
library(gt)


# Scrape UFC Rankings from ESPN API ---------------------------------------
ufc_rankings_url <-  "http://site.api.espn.com/apis/site/v2/sports/mma/ufc/rankings"
raw_ranking_json <- rjson::fromJSON(file = ufc_rankings_url)
mma_logo <- pluck(raw_ranking_json, "sports",1, "logos",1,"href")
ufc_league_full_name <- pluck(raw_ranking_json, "leagues", 1, "name") 
ufc_league_abbr <- pluck(raw_ranking_json, "leagues", 1, "abbreviation") 
ufc_league_short_name <- pluck(raw_ranking_json, "leagues", 1, "shortName") 

# Rankings 
rankings <- pluck(raw_ranking_json, "rankings") %>%  
    enframe()
rankings <- rankings %>% 
    unnest_wider(value, names_sep = "_") %>% 
    unnest_wider(value_weightClass, names_sep = "_")


#  Clean it 
rankings <- rankings%>% 
    unnest_longer(value_ranks) %>% 
    unnest_wider(value_ranks) %>% 
    unnest_wider(athlete, names_sep = "_") %>% 
    select(starts_with("athlete"),everything(),-where(is.list), -c(name, value_id)) 

# Example : HeavyWeight fighters standing
( hw_fighters <- rankings %>%
        filter(value_weightClass_slug == "heavyweight"))


# Scrape All MMA fighters profil from ESPN Website ------------------------
(fighters_rows <- str_c("http://www.espn.com/mma/fighters?search=", letters) %>% 
     map( ~read_html(.x) %>% 
              html_nodes("tr.evenrow")
     ) %>% 
     append(
         str_c("http://www.espn.com/mma/fighters?search=", letters) %>% 
             map( ~read_html(.x) %>% 
                      html_nodes("tr.oddrow")
             )
     )
)

# https://stackoverflow.com/questions/43427726/concatenate-vectors-from-a-lists-of-lists
# concatenate vectors from a lists of lists
vecs <- unlist(fighters_rows, recursive = F)
(lapply(unique(names(vecs)), function(name) do.call(c, vecs[name == names(vecs)])))

# Retrieve Player Links
retrieve_player_infos <- function(player) {
    (player_infos <- player %>% 
         html_nodes("td")
    )
    (player_name <- player_infos %>% 
            pluck(1) %>% 
            html_node("a") %>% 
            html_text()
    )  
    (player_link <- player_infos %>% 
            pluck(1) %>% 
            html_node("a") %>% 
            html_attr("href") 
    )  
    (player_country <- player_infos %>% 
            pluck(2) %>% 
            html_text()
    )
    list("player_name" = player_name, "player_link" = player_link, "player_country" = player_country)
}

# Retrieve links for all fighters
fighters_dataset <- vecs %>% 
    map(retrieve_player_infos) %>% 
    bind_rows() %>% 
    arrange(player_name) %>% 
    mutate(
        id = as.integer(str_extract(player_link, "(\\d+)" )), # Extract id 
        player_link = str_c("https://www.espn.com", player_link)
    ) 



# Example : French fighters 
(fighters_dataset %>% 
        filter(player_country == "FRA") 
)

# Save the dataset 
# write_csv(fighters_dataset, "Dataset/mma_fighters.csv")
# saveRDS(fighters_dataset,"Dataset/mma_fighters.rds")

# Get a specifical fighter info
get_fighter_infos <- function(fighter_name){
    fighters_dataset %>% 
        filter(player_name == fighter_name)
}

# Get Fighter Individual Stats
get_fighter_stats <- function(fighter_id) {
    fighter_url <- glue("https://www.espn.com/mma/fighter/stats/_/id/{fighter_id}")
    tables <- fighter_url %>% 
        read_html() %>% 
        html_nodes("table") %>% 
        html_table(header = T) %>% 
        enframe()
    
    stats <- tables %>% 
        pull(value) %>% 
        map_dfc(pluck) %>%
        select(-c(17:20,33:36))  # Remove date 
    
    colnames(stats) <-  names(stats) %>% 
        str_replace("\\.+\\d","")
    
    stats
}

# Summarise KD BODY HEAD LEG
summarise_player_stats <- function(stats) {
    stats %>% 
        summarise(
            last_5_kds = sum(head(as.numeric(KD),5)),
            last_5_body_pct = mean(head(parse_number(`%BODY`),5)),
            last_5_head_pct = mean(head(parse_number(`%HEAD`),5)),
            last_5_leg_pct = mean(head(parse_number(`%LEG`),5)),
            nb_wins = sum(Res == "W"),
            nb_loses = sum(Res == "L")
        )
    
}
