First, load some R packages I will need later:

library(dplyr) 
library(purrr)
library(rvest)
library(httr)
library(stringr)
library(glue)

The following is a function which goes to the helpful page https://boardgamegeek.com/plays/bygame/subtype/boardgame/start/2018-01-01/end/2018-12-31?sortby=distinctusers for a given year, retrieves all the IDs of the games and the number of unqiue players, and then makes a call to the XML API to get the publication years.

get_players <- function(year) {
  #first create the link with the appropriate year substituted in and read that page in
  players_link <- glue('https://boardgamegeek.com/plays/bygame/subtype/boardgame/start/{year}-01-01/end/{year}-12-31?sortby=distinctusers', year = year)
  
  players_page <- read_html(players_link) 
  
  
  # strip out all the game IDs (used https://selectorgadget.com/ to get the matching path)
  ids <- players_page %>%
    html_nodes('#main_content td:nth-child(3) a') %>%
    html_attr('href') %>%
    str_replace('/playstats/thing/','')
  
  # same for the number of unique players
  players <- players_page %>%
    html_nodes('#main_content td:nth-child(3) a') %>%
    html_text() %>%
    str_replace('\n\t\t','') %>%
    as.integer()
  
  # now get the XML API page for the IDs pulled out - it can do them all in one call
  ids_xml <- GET('https://boardgamegeek.com',
                       accept_xml(),
                       path = '/xmlapi2/thing',
                       query = list('id' = paste(ids, collapse = ',')))
  
  # from the XML page returned pull out the publication year
  pubyear <- content(ids_xml) %>%
    xml_find_all('//item/yearpublished') %>%
    xml_attr('value') %>%
    as.integer()
  
  # and the title
  title <- content(ids_xml) %>%
    xml_find_all('//item/name[@type="primary"]') %>%
    xml_attr('value')
  
  # and now stick everything in a data frame
  data_frame(title, players, pubyear)
}

With this function created, I can now just repeat it for all the years I’m interested in, combining them into a single data frame:

players_df <- map_df(2005:2018, get_players, .id = 'year') %>%
  mutate(year = as.integer(year) + 2004)

And finally I do a bit of manipulation to get only the ‘evergreen games’ and display them in the desired format.

players_df %>%
  filter(year - pubyear >= 10) %>%
  arrange(desc(year), desc(players)) %>%
  group_by(year) %>%
  top_n(10, players) %>%
  ungroup()
LS0tDQp0aXRsZTogIkV2ZXJncmVlbiBnYW1lcyINCm91dHB1dDogaHRtbF9ub3RlYm9vaw0KLS0tDQoNCkZpcnN0LCBsb2FkIHNvbWUgUiBwYWNrYWdlcyBJIHdpbGwgbmVlZCBsYXRlcjoNCg0KYGBge3IgbWVzc2FnZSA9IEZBTFNFfQ0KDQpsaWJyYXJ5KGRwbHlyKSANCmxpYnJhcnkocHVycnIpDQpsaWJyYXJ5KHJ2ZXN0KQ0KbGlicmFyeShodHRyKQ0KbGlicmFyeShzdHJpbmdyKQ0KbGlicmFyeShnbHVlKQ0KDQpgYGANCg0KVGhlIGZvbGxvd2luZyBpcyBhIGZ1bmN0aW9uIHdoaWNoIGdvZXMgdG8gdGhlIGhlbHBmdWwgcGFnZSBodHRwczovL2JvYXJkZ2FtZWdlZWsuY29tL3BsYXlzL2J5Z2FtZS9zdWJ0eXBlL2JvYXJkZ2FtZS9zdGFydC8yMDE4LTAxLTAxL2VuZC8yMDE4LTEyLTMxP3NvcnRieT1kaXN0aW5jdHVzZXJzIGZvciBhIGdpdmVuIHllYXIsIHJldHJpZXZlcyBhbGwgdGhlIElEcyBvZiB0aGUgZ2FtZXMgYW5kIHRoZSBudW1iZXIgb2YgdW5xaXVlIHBsYXllcnMsIGFuZCB0aGVuIG1ha2VzIGEgY2FsbCB0byB0aGUgWE1MIEFQSSB0byBnZXQgdGhlIHB1YmxpY2F0aW9uIHllYXJzLg0KDQpgYGB7cn0NCg0KZ2V0X3BsYXllcnMgPC0gZnVuY3Rpb24oeWVhcikgew0KICAjZmlyc3QgY3JlYXRlIHRoZSBsaW5rIHdpdGggdGhlIGFwcHJvcHJpYXRlIHllYXIgc3Vic3RpdHV0ZWQgaW4gYW5kIHJlYWQgdGhhdCBwYWdlIGluDQogIHBsYXllcnNfbGluayA8LSBnbHVlKCdodHRwczovL2JvYXJkZ2FtZWdlZWsuY29tL3BsYXlzL2J5Z2FtZS9zdWJ0eXBlL2JvYXJkZ2FtZS9zdGFydC97eWVhcn0tMDEtMDEvZW5kL3t5ZWFyfS0xMi0zMT9zb3J0Ynk9ZGlzdGluY3R1c2VycycsIHllYXIgPSB5ZWFyKQ0KICANCiAgcGxheWVyc19wYWdlIDwtIHJlYWRfaHRtbChwbGF5ZXJzX2xpbmspIA0KICANCiAgDQogICMgc3RyaXAgb3V0IGFsbCB0aGUgZ2FtZSBJRHMgKHVzZWQgaHR0cHM6Ly9zZWxlY3RvcmdhZGdldC5jb20vIHRvIGdldCB0aGUgbWF0Y2hpbmcgcGF0aCkNCiAgaWRzIDwtIHBsYXllcnNfcGFnZSAlPiUNCiAgICBodG1sX25vZGVzKCcjbWFpbl9jb250ZW50IHRkOm50aC1jaGlsZCgzKSBhJykgJT4lDQogICAgaHRtbF9hdHRyKCdocmVmJykgJT4lDQogICAgc3RyX3JlcGxhY2UoJy9wbGF5c3RhdHMvdGhpbmcvJywnJykNCiAgDQogICMgc2FtZSBmb3IgdGhlIG51bWJlciBvZiB1bmlxdWUgcGxheWVycw0KICBwbGF5ZXJzIDwtIHBsYXllcnNfcGFnZSAlPiUNCiAgICBodG1sX25vZGVzKCcjbWFpbl9jb250ZW50IHRkOm50aC1jaGlsZCgzKSBhJykgJT4lDQogICAgaHRtbF90ZXh0KCkgJT4lDQogICAgc3RyX3JlcGxhY2UoJ1xuXHRcdCcsJycpICU+JQ0KICAgIGFzLmludGVnZXIoKQ0KICANCiAgIyBub3cgZ2V0IHRoZSBYTUwgQVBJIHBhZ2UgZm9yIHRoZSBJRHMgcHVsbGVkIG91dCAtIGl0IGNhbiBkbyB0aGVtIGFsbCBpbiBvbmUgY2FsbA0KICBpZHNfeG1sIDwtIEdFVCgnaHR0cHM6Ly9ib2FyZGdhbWVnZWVrLmNvbScsDQogICAgICAgICAgICAgICAgICAgICAgIGFjY2VwdF94bWwoKSwNCiAgICAgICAgICAgICAgICAgICAgICAgcGF0aCA9ICcveG1sYXBpMi90aGluZycsDQogICAgICAgICAgICAgICAgICAgICAgIHF1ZXJ5ID0gbGlzdCgnaWQnID0gcGFzdGUoaWRzLCBjb2xsYXBzZSA9ICcsJykpKQ0KICANCiAgIyBmcm9tIHRoZSBYTUwgcGFnZSByZXR1cm5lZCBwdWxsIG91dCB0aGUgcHVibGljYXRpb24geWVhcg0KICBwdWJ5ZWFyIDwtIGNvbnRlbnQoaWRzX3htbCkgJT4lDQogICAgeG1sX2ZpbmRfYWxsKCcvL2l0ZW0veWVhcnB1Ymxpc2hlZCcpICU+JQ0KICAgIHhtbF9hdHRyKCd2YWx1ZScpICU+JQ0KICAgIGFzLmludGVnZXIoKQ0KICANCiAgIyBhbmQgdGhlIHRpdGxlDQogIHRpdGxlIDwtIGNvbnRlbnQoaWRzX3htbCkgJT4lDQogICAgeG1sX2ZpbmRfYWxsKCcvL2l0ZW0vbmFtZVtAdHlwZT0icHJpbWFyeSJdJykgJT4lDQogICAgeG1sX2F0dHIoJ3ZhbHVlJykNCiAgDQogICMgYW5kIG5vdyBzdGljayBldmVyeXRoaW5nIGluIGEgZGF0YSBmcmFtZQ0KICBkYXRhX2ZyYW1lKHRpdGxlLCBwbGF5ZXJzLCBwdWJ5ZWFyKQ0KfQ0KDQpgYGANCg0KV2l0aCB0aGlzIGZ1bmN0aW9uIGNyZWF0ZWQsIEkgY2FuIG5vdyBqdXN0IHJlcGVhdCBpdCBmb3IgYWxsIHRoZSB5ZWFycyBJJ20gaW50ZXJlc3RlZCBpbiwgY29tYmluaW5nIHRoZW0gaW50byBhIHNpbmdsZSBkYXRhIGZyYW1lOg0KDQpgYGB7cn0NCg0KcGxheWVyc19kZiA8LSBtYXBfZGYoMjAwNToyMDE4LCBnZXRfcGxheWVycywgLmlkID0gJ3llYXInKSAlPiUNCiAgbXV0YXRlKHllYXIgPSBhcy5pbnRlZ2VyKHllYXIpICsgMjAwNCkNCg0KYGBgDQoNCkFuZCBmaW5hbGx5IEkgZG8gYSBiaXQgb2YgbWFuaXB1bGF0aW9uIHRvIGdldCBvbmx5IHRoZSAnZXZlcmdyZWVuIGdhbWVzJyBhbmQgZGlzcGxheSB0aGVtIGluIHRoZSBkZXNpcmVkIGZvcm1hdC4NCg0KYGBge3J9DQoNCnBsYXllcnNfZGYgJT4lDQogIGZpbHRlcih5ZWFyIC0gcHVieWVhciA+PSAxMCkgJT4lDQogIGFycmFuZ2UoZGVzYyh5ZWFyKSwgZGVzYyhwbGF5ZXJzKSkgJT4lDQogIGdyb3VwX2J5KHllYXIpICU+JQ0KICB0b3BfbigxMCwgcGxheWVycykgJT4lDQogIHVuZ3JvdXAoKQ0KDQpgYGANCg==