Skip to content

Instantly share code, notes, and snippets.

@DavZim
Created May 28, 2019 13:27
Show Gist options
  • Save DavZim/070b2b6c8496a7ae2d7c2c34815fd370 to your computer and use it in GitHub Desktop.
Save DavZim/070b2b6c8496a7ae2d7c2c34815fd370 to your computer and use it in GitHub Desktop.
Downloads the data from the Bundeswahlleiter and creates some quick plots
library(tidyverse) # for data manipulation
library(rvest)     # for web scraping of the bundeswahlleiter
library(GGally)    # for the correlelogram

#' Downloads the data from the Bundeswahlleiter
#' 
#' @param url the url to download, used internally only as the function calls itself recursively, the url is the url for the respective page,
#' i.e., https://www.bundeswahlleiter.de/europawahlen/2019/ergebnisse/bund-99/land-2.html or
#' https://www.bundeswahlleiter.de/europawahlen/2019/ergebnisse/bund-99/land-8/kreis-8435.html
#' 
#' @return a nested tibble of the european election results
#' @export
#' 
#' @examples
#' df <- download_wahlleiter()
download_wahlleiter <- function(url = NA) {
  base_url <- "https://www.bundeswahlleiter.de/europawahlen/2019/ergebnisse/bund-99/"
  if (is.na(url)) {
    countries <- 1:16
    urls <- paste0(base_url, paste0("land-", countries, ".html"))
    
    res <- map_dfr(urls, download_wahlleiter)
    return(res)
  }
  
  dd <- read_html(url)
  
  ov <- c("Wahlberechtigte", "Wähler", "Ungültige", "Gültige")
  name_guess <- dd %>% html_nodes(xpath = "/html/body/div[1]/div/main/nav/ul/li[2]/div[1]/div/div/button/span") %>% html_text()
  
  kreis_level <- !name_guess %in% c("Baden-Württemberg", "Bayern", "Berlin", "Brandenburg", "Bremen", "Hamburg", "Hessen", "Mecklenburg-Vorpommern", "Niedersachsen", "Nordrhein-Westfalen", 
  "Rheinland-Pfalz", "Saarland", "Sachsen", "Sachsen-Anhalt", "Schleswig-Holstein", "Thüringen")
  
  html_data <- dd %>% 
    xml_children() %>% 
    xml_children() %>% 
    xml_children() %>% 
    xml_children() %>%
    xml_children() %>% 
    xml_find_all("//figure")
  
  data <- html_data[[length(html_data)]] %>% 
    xml_children() %>% 
    .[[1]] %>% 
    html_table(fill = TRUE) %>% 
    set_names(c("grp", "count_2019", "perc_2019", "count_2014", "perc_2014", "chg")) %>% 
    as_tibble() %>% 
    slice(-1) %>% 
    mutate_at(vars(-grp), function(x) {
      # parses the german number formats
      xx <- x %>% 
        str_replace_all("\\.", "") %>% 
        str_replace_all(",", ".")
      xx[xx == "±0.0"] <- 0
      xx[xx == "-"] <- NA
      as.numeric(xx)
    })
  
  data_overview <- data %>% filter(grp %in% ov)
  data_result <- data %>% filter(!grp %in% ov)
  
  # either parses the kreis level data or the county data
  if (kreis_level) {
    kreis <- dd %>% html_nodes(xpath = "/html/body/div[1]/div/main/nav/ul/li[3]/div/div/div/button/span") %>% html_text()
    cat("\t", kreis, "...\n")
    
    # Sys.sleep(runif(1, 0, 0.1))
    res <- tibble(
      kreis = kreis, 
      kreis_url = url,
      ballot_count = list(data_overview),
      result = list(data_result)
    )
    
  } else {
    # land level
    land <- dd %>% html_nodes(xpath = "/html/body/div[1]/div/main/nav/ul/li[2]/div[1]/div/div/button/span") %>% html_text()
    cat("Scraping", land, "...\n")
    kreis_urls <- paste0(base_url,
                         dd %>% html_nodes(xpath = "/html/body/div[1]/div/main/div[2]") %>% as.character() %>% str_extract_all("(?<=a href=\\\")[^\">]*") %>% unlist())
    
    kreis_data <- map_dfr(kreis_urls, download_wahlleiter)
    
    # Sys.sleep(runif(1, 0, 1))
    res <- tibble(
      country = "Germany",
      land = land,
      land_url = url,
      ballot_count = list(data_overview),
      result = list(data_result),
      detailed = list(kreis_data)
    )
  }
  return(res)
}

## Downloads the data ----
file <- "wahlleiter_data.RDS"

# download only if the file doesnt exist already
if (file.exists(file)) {
  df <- readRDS(file)
} else {
  df <- download_wahlleiter()
  saveRDS(df, file)
}
#> Scraping Schleswig-Holstein ...
#>   Dithmarschen ...
#>   Flensburg, Stadt ...
#>   Herzogtum Lauenburg ...
#>   Kiel, Landeshauptstadt ...
#>   Lübeck, Hansestadt ...
#>   Neumünster, Stadt ...
#>   Nordfriesland ...
#>   Ostholstein ...
#>   Pinneberg ...
#>   Plön ...
#>   Rendsburg-Eckernförde ...
#>   Schleswig-Flensburg ...
#>   Segeberg ...
#>   Steinburg ...
#>   Stormarn ...
#> Scraping Hamburg ...
#>   Hamburg, Freie und Hansestadt ...
#> Scraping Niedersachsen ...
#>   Ammerland ...
#>   Aurich ...
#>   Braunschweig, Stadt ...
#>   Celle ...
#>   Cloppenburg ...
#>   Cuxhaven ...
#>   Delmenhorst, Stadt ...
#>   Diepholz ...
#>   Emden, Stadt ...
#>   Emsland ...
#>   Friesland ...
#>   Gifhorn ...
#>   Goslar ...
#>   Göttingen ...
#>   Grafschaft Bentheim ...
#>   Hameln-Pyrmont ...
#>   Harburg ...
#>   Heidekreis ...
#>   Helmstedt ...
#>   Hildesheim ...
#>   Holzminden ...
#>   Leer ...
#>   Lüchow-Dannenberg ...
#>   Lüneburg ...
#>   Nienburg (Weser) ...
#>   Northeim ...
#>   Oldenburg ...
#>   Oldenburg (Oldenburg), Stadt ...
#>   Osnabrück ...
#>   Osnabrück, Stadt ...
#>   Osterholz ...
#>   Peine ...
#>   Region Hannover ...
#>   Rotenburg (Wümme) ...
#>   Salzgitter, Stadt ...
#>   Schaumburg ...
#>   Stade ...
#>   Uelzen ...
#>   Vechta ...
#>   Verden ...
#>   Wesermarsch ...
#>   Wilhelmshaven, Stadt ...
#>   Wittmund ...
#>   Wolfenbüttel ...
#>   Wolfsburg, Stadt ...
#> Scraping Bremen ...
#>   Bremen, Stadt ...
#>   Bremerhaven, Stadt ...
#> Scraping Nordrhein-Westfalen ...
#>   Bielefeld, Stadt ...
#>   Bochum, Stadt ...
#>   Bonn, Stadt ...
#>   Borken ...
#>   Bottrop, Stadt ...
#>   Coesfeld ...
#>   Dortmund, Stadt ...
#>   Duisburg, Stadt ...
#>   Düren ...
#>   Düsseldorf, Stadt ...
#>   Ennepe-Ruhr-Kreis ...
#>   Essen, Stadt ...
#>   Euskirchen ...
#>   Gelsenkirchen, Stadt ...
#>   Gütersloh ...
#>   Hagen, Stadt der FernUniversität ...
#>   Hamm, Stadt ...
#>   Heinsberg ...
#>   Herford ...
#>   Herne, Stadt ...
#>   Hochsauerlandkreis ...
#>   Höxter ...
#>   Kleve ...
#>   Köln, Stadt ...
#>   Krefeld, Stadt ...
#>   Leverkusen, Stadt ...
#>   Lippe ...
#>   Märkischer Kreis ...
#>   Mettmann ...
#>   Minden-Lübbecke ...
#>   Mönchengladbach, Stadt ...
#>   Mülheim an der Ruhr, Stadt ...
#>   Münster, Stadt ...
#>   Oberbergischer Kreis ...
#>   Oberhausen, Stadt ...
#>   Olpe ...
#>   Paderborn ...
#>   Recklinghausen ...
#>   Remscheid, Stadt ...
#>   Rhein-Erft-Kreis ...
#>   Rheinisch-Bergischer Kreis ...
#>   Rhein-Kreis Neuss ...
#>   Rhein-Sieg-Kreis ...
#>   Siegen-Wittgenstein ...
#>   Soest ...
#>   Solingen, Klingenstadt ...
#>   Städteregion Aachen ...
#>   Steinfurt ...
#>   Unna ...
#>   Viersen ...
#>   Warendorf ...
#>   Wesel ...
#>   Wuppertal, Stadt ...
#> Scraping Hessen ...
#>   Bergstraße ...
#>   Darmstadt, Wissenschaftsstadt ...
#>   Darmstadt-Dieburg ...
#>   Frankfurt am Main, Stadt ...
#>   Fulda ...
#>   Gießen ...
#>   Groß-Gerau ...
#>   Hersfeld-Rotenburg ...
#>   Hochtaunuskreis ...
#>   Kassel ...
#>   Kassel, documenta-Stadt ...
#>   Lahn-Dill-Kreis ...
#>   Limburg-Weilburg ...
#>   Main-Kinzig-Kreis ...
#>   Main-Taunus-Kreis ...
#>   Marburg-Biedenkopf ...
#>   Odenwaldkreis ...
#>   Offenbach ...
#>   Offenbach am Main, Stadt ...
#>   Rheingau-Taunus-Kreis ...
#>   Schwalm-Eder-Kreis ...
#>   Vogelsbergkreis ...
#>   Waldeck-Frankenberg ...
#>   Werra-Meißner-Kreis ...
#>   Wetteraukreis ...
#>   Wiesbaden, Landeshauptstadt ...
#> Scraping Rheinland-Pfalz ...
#>   Ahrweiler ...
#>   Altenkirchen (Westerwald) ...
#>   Alzey-Worms ...
#>   Bad Dürkheim ...
#>   Bad Kreuznach ...
#>   Bernkastel-Wittlich ...
#>   Birkenfeld ...
#>   Cochem-Zell ...
#>   Donnersbergkreis ...
#>   Eifelkreis Bitburg-Prüm ...
#>   Frankenthal (Pfalz), kreisfreie Stadt ...
#>   Germersheim ...
#>   Kaiserslautern ...
#>   Kaiserslautern, kreisfreie Stadt ...
#>   Koblenz, kreisfreie Stadt ...
#>   Kusel ...
#>   Landau in der Pfalz, kreisfreie Stadt ...
#>   Ludwigshafen am Rhein, kreisfreie Stadt ...
#>   Mainz, kreisfreie Stadt ...
#>   Mainz-Bingen ...
#>   Mayen-Koblenz ...
#>   Neustadt an der Weinstraße, kreisfreie Stadt ...
#>   Neuwied ...
#>   Pirmasens, kreisfreie Stadt ...
#>   Rhein-Hunsrück-Kreis ...
#>   Rhein-Lahn-Kreis ...
#>   Rhein-Pfalz-Kreis ...
#>   Speyer, kreisfreie Stadt ...
#>   Südliche Weinstraße ...
#>   Südwestpfalz ...
#>   Trier, kreisfreie Stadt ...
#>   Trier-Saarburg ...
#>   Vulkaneifel ...
#>   Westerwaldkreis ...
#>   Worms, kreisfreie Stadt ...
#>   Zweibrücken, kreisfreie Stadt ...
#> Scraping Baden-Württemberg ...
#>   Alb-Donau-Kreis ...
#>   Baden-Baden, Stadt ...
#>   Biberach ...
#>   Böblingen ...
#>   Bodenseekreis ...
#>   Breisgau-Hochschwarzwald ...
#>   Calw ...
#>   Emmendingen ...
#>   Enzkreis ...
#>   Esslingen ...
#>   Freiburg im Breisgau, Stadt ...
#>   Freudenstadt ...
#>   Göppingen ...
#>   Heidelberg, Stadt ...
#>   Heidenheim ...
#>   Heilbronn ...
#>   Heilbronn, Stadt ...
#>   Hohenlohekreis ...
#>   Karlsruhe ...
#>   Karlsruhe, Stadt ...
#>   Konstanz ...
#>   Lörrach ...
#>   Ludwigsburg ...
#>   Main-Tauber-Kreis ...
#>   Mannheim, Universitätsstadt ...
#>   Neckar-Odenwald-Kreis ...
#>   Ortenaukreis ...
#>   Ostalbkreis ...
#>   Pforzheim, Stadt ...
#>   Rastatt ...
#>   Ravensburg ...
#>   Rems-Murr-Kreis ...
#>   Reutlingen ...
#>   Rhein-Neckar-Kreis ...
#>   Rottweil ...
#>   Schwäbisch Hall ...
#>   Schwarzwald-Baar-Kreis ...
#>   Sigmaringen ...
#>   Stuttgart, Landeshauptstadt ...
#>   Tübingen ...
#>   Tuttlingen ...
#>   Ulm, Universitätsstadt ...
#>   Waldshut ...
#>   Zollernalbkreis ...
#> Scraping Bayern ...
#>   Aichach-Friedberg ...
#>   Altötting ...
#>   Amberg, Stadt ...
#>   Amberg-Sulzbach ...
#>   Ansbach ...
#>   Ansbach, Stadt ...
#>   Aschaffenburg ...
#>   Aschaffenburg, Stadt ...
#>   Augsburg ...
#>   Augsburg, Stadt ...
#>   Bad Kissingen ...
#>   Bad Tölz-Wolfratshausen ...
#>   Bamberg ...
#>   Bamberg, Stadt ...
#>   Bayreuth ...
#>   Bayreuth, Stadt ...
#>   Berchtesgadener Land ...
#>   Cham ...
#>   Coburg ...
#>   Coburg, Stadt ...
#>   Dachau ...
#>   Deggendorf ...
#>   Dillingen a.d.Donau ...
#>   Dingolfing-Landau ...
#>   Donau-Ries ...
#>   Ebersberg ...
#>   Eichstätt ...
#>   Erding ...
#>   Erlangen, Stadt ...
#>   Erlangen-Höchstadt ...
#>   Forchheim ...
#>   Freising ...
#>   Freyung-Grafenau ...
#>   Fürstenfeldbruck ...
#>   Fürth ...
#>   Fürth, Stadt ...
#>   Garmisch-Partenkirchen ...
#>   Günzburg ...
#>   Haßberge ...
#>   Hof ...
#>   Hof, Stadt ...
#>   Ingolstadt, Stadt ...
#>   Kaufbeuren, Stadt ...
#>   Kelheim ...
#>   Kempten (Allgäu), Stadt ...
#>   Kitzingen ...
#>   Kronach ...
#>   Kulmbach ...
#>   Landsberg am Lech ...
#>   Landshut ...
#>   Landshut, Stadt ...
#>   Lichtenfels ...
#>   Lindau (Bodensee) ...
#>   Main-Spessart ...
#>   Memmingen, Stadt ...
#>   Miesbach ...
#>   Miltenberg ...
#>   Mühldorf a.Inn ...
#>   München ...
#>   München, Landeshauptstadt ...
#>   Neuburg-Schrobenhausen ...
#>   Neumarkt i.d.OPf. ...
#>   Neustadt a.d.Aisch-Bad Windsheim ...
#>   Neustadt a.d.Waldnaab ...
#>   Neu-Ulm ...
#>   Nürnberg, Stadt ...
#>   Nürnberger Land ...
#>   Oberallgäu ...
#>   Ostallgäu ...
#>   Passau ...
#>   Passau, Stadt ...
#>   Pfaffenhofen a.d.Ilm ...
#>   Regen ...
#>   Regensburg ...
#>   Regensburg, Stadt ...
#>   Rhön-Grabfeld ...
#>   Rosenheim ...
#>   Rosenheim, Stadt ...
#>   Roth ...
#>   Rottal-Inn ...
#>   Schwabach, Stadt ...
#>   Schwandorf ...
#>   Schweinfurt ...
#>   Schweinfurt, Stadt ...
#>   Starnberg ...
#>   Straubing, Stadt ...
#>   Straubing-Bogen ...
#>   Tirschenreuth ...
#>   Traunstein ...
#>   Unterallgäu ...
#>   Weiden i.d.OPf., Stadt ...
#>   Weilheim-Schongau ...
#>   Weißenburg-Gunzenhausen ...
#>   Wunsiedel i.Fichtelgebirge ...
#>   Würzburg ...
#>   Würzburg, Stadt ...
#> Scraping Saarland ...
#>   Merzig-Wadern ...
#>   Neunkirchen ...
#>   Regionalverband Saarbrücken ...
#>   Saarlouis ...
#>   Saarpfalz-Kreis ...
#>   St. Wendel ...
#> Scraping Berlin ...
#>   Berlin, Stadt ...
#> Scraping Brandenburg ...
#>   Barnim ...
#>   Brandenburg an der Havel, Stadt ...
#>   Cottbus, Stadt ...
#>   Dahme-Spreewald ...
#>   Elbe-Elster ...
#>   Frankfurt (Oder), Stadt ...
#>   Havelland ...
#>   Märkisch-Oderland ...
#>   Oberhavel ...
#>   Oberspreewald-Lausitz ...
#>   Oder-Spree ...
#>   Ostprignitz-Ruppin ...
#>   Potsdam, Stadt ...
#>   Potsdam-Mittelmark ...
#>   Prignitz ...
#>   Spree-Neiße ...
#>   Teltow-Fläming ...
#>   Uckermark ...
#> Scraping Mecklenburg-Vorpommern ...
#>   Landkreis Rostock ...
#>   Ludwigslust-Parchim ...
#>   Mecklenburgische Seenplatte ...
#>   Nordwestmecklenburg ...
#>   Rostock ...
#>   Schwerin ...
#>   Vorpommern-Greifswald ...
#>   Vorpommern-Rügen ...
#> Scraping Sachsen ...
#>   Bautzen ...
#>   Chemnitz, Stadt ...
#>   Dresden, Stadt ...
#>   Erzgebirgskreis ...
#>   Görlitz ...
#>   Leipzig ...
#>   Leipzig, Stadt ...
#>   Meißen ...
#>   Mittelsachsen ...
#>   Nordsachsen ...
#>   Sächsische Schweiz-Osterzgebirge ...
#>   Vogtlandkreis ...
#>   Zwickau ...
#> Scraping Sachsen-Anhalt ...
#>   Altmarkkreis Salzwedel ...
#>   Anhalt-Bitterfeld ...
#>   Börde ...
#>   Burgenlandkreis ...
#>   Dessau-Roßlau, Stadt ...
#>   Halle (Saale), Stadt ...
#>   Harz ...
#>   Jerichower Land ...
#>   Magdeburg, Landeshauptstadt ...
#>   Mansfeld-Südharz ...
#>   Saalekreis ...
#>   Salzlandkreis ...
#>   Stendal ...
#>   Wittenberg ...
#> Scraping Thüringen ...
#>   Altenburger Land ...
#>   Eichsfeld ...
#>   Eisenach, Stadt ...
#>   Erfurt, Stadt ...
#>   Gera, Stadt ...
#>   Gotha ...
#>   Greiz ...
#>   Hildburghausen ...
#>   Ilm-Kreis ...
#>   Jena, Stadt ...
#>   Kyffhäuserkreis ...
#>   Nordhausen ...
#>   Saale-Holzland-Kreis ...
#>   Saale-Orla-Kreis ...
#>   Saalfeld-Rudolstadt ...
#>   Schmalkalden-Meiningen ...
#>   Sömmerda ...
#>   Sonneberg ...
#>   Suhl, Stadt ...
#>   Unstrut-Hainich-Kreis ...
#>   Wartburgkreis ...
#>   Weimar, Stadt ...
#>   Weimarer Land ...
df
#> # A tibble: 16 x 6
#>    country land      land_url              ballot_count  result   detailed 
#>    <chr>   <chr>     <chr>                 <list>        <list>   <list>   
#>  1 Germany Schleswi… https://www.bundeswa… <tibble [4 ×… <tibble… <tibble …
#>  2 Germany Hamburg   https://www.bundeswa… <tibble [4 ×… <tibble… <tibble …
#>  3 Germany Niedersa… https://www.bundeswa… <tibble [4 ×… <tibble… <tibble …
#>  4 Germany Bremen    https://www.bundeswa… <tibble [4 ×… <tibble… <tibble …
#>  5 Germany Nordrhei… https://www.bundeswa… <tibble [4 ×… <tibble… <tibble …
#>  6 Germany Hessen    https://www.bundeswa… <tibble [4 ×… <tibble… <tibble …
#>  7 Germany Rheinlan… https://www.bundeswa… <tibble [4 ×… <tibble… <tibble …
#>  8 Germany Baden-Wü… https://www.bundeswa… <tibble [4 ×… <tibble… <tibble …
#>  9 Germany Bayern    https://www.bundeswa… <tibble [4 ×… <tibble… <tibble …
#> 10 Germany Saarland  https://www.bundeswa… <tibble [4 ×… <tibble… <tibble …
#> 11 Germany Berlin    https://www.bundeswa… <tibble [4 ×… <tibble… <tibble …
#> 12 Germany Brandenb… https://www.bundeswa… <tibble [4 ×… <tibble… <tibble …
#> 13 Germany Mecklenb… https://www.bundeswa… <tibble [4 ×… <tibble… <tibble …
#> 14 Germany Sachsen   https://www.bundeswa… <tibble [4 ×… <tibble… <tibble …
#> 15 Germany Sachsen-… https://www.bundeswa… <tibble [4 ×… <tibble… <tibble …
#> 16 Germany Thüringen https://www.bundeswa… <tibble [4 ×… <tibble… <tibble …


df_kreis <- df %>% 
  select(country, land, detailed) %>% 
  unnest(detailed) %>% 
  unnest(result)

df_kreis
#> # A tibble: 16,441 x 10
#>    country land  kreis kreis_url grp   count_2019 perc_2019 count_2014
#>    <chr>   <chr> <chr> <chr>     <chr>      <dbl>     <dbl>      <dbl>
#>  1 Germany Schl… Dith… https://… CDU        17955      31.1      17958
#>  2 Germany Schl… Dith… https://… SPD        10294      17.8      12381
#>  3 Germany Schl… Dith… https://… GRÜNE      12121      21         3432
#>  4 Germany Schl… Dith… https://… AfD         5121       8.9       2325
#>  5 Germany Schl… Dith… https://… DIE …       2002       3.5       1775
#>  6 Germany Schl… Dith… https://… FDP         4498       7.8       1734
#>  7 Germany Schl… Dith… https://… PIRA…        539       0.9        571
#>  8 Germany Schl… Dith… https://… Tier…        886       1.5        574
#>  9 Germany Schl… Dith… https://… FAMI…        613       1.1        403
#> 10 Germany Schl… Dith… https://… Die …       1089       1.9        224
#> # … with 16,431 more rows, and 2 more variables: perc_2014 <dbl>,
#> #   chg <dbl>

# how many ppl have voted in Germany?
# Does it match the 37,389,231 as reported on https://www.bundeswahlleiter.de/europawahlen/2019/ergebnisse/bund-99.html 
df_kreis %>% 
  summarise(valid_votes = sum(count_2019, na.rm = TRUE))
#> # A tibble: 1 x 1
#>   valid_votes
#>         <dbl>
#> 1    37389231

# construct the correlations
df_kreis %>%
  select(land, kreis, grp, count_2019) %>% 
  spread(key = grp, value = count_2019) %>% 
  select(-land, -kreis) %>% 
  # cor(use = "pairwise.complete.obs") %>% 
  ggcorr()

# take only the most popular parties
top_parties <- df_kreis %>% 
  group_by(grp) %>% 
  summarise(count = sum(count_2019, na.rm = TRUE)) %>% 
  arrange(desc(count)) %>% 
  top_n(10, count) %>% 
  pull(grp)

df_kreis %>%
  filter(grp %in% top_parties) %>% 
  select(land, kreis, grp, count_2019) %>% 
  spread(key = grp, value = count_2019) %>% 
  select(-land, -kreis) %>% 
  # cor(use = "pairwise.complete.obs") %>% 
  ggcorr()

Created on 2019-05-28 by the reprex package (v0.2.1)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment