October, 2015

Today

Gathering data from the web

Webscraping

  • easy: using css selectors
  • old approach: using xpath

Gathering data from APIs

Rules

Rules of web scraping

  1. You should check a site's terms and conditions before you scrape them. It's their data and they likely have some rules to govern it.
  2. Be nice - A computer will send web requests much quicker than a user can. Make sure you space out your requests a bit so that you don't hammer the site's server.
  3. Scrapers break - Sites change their layout all the time. If that happens, be prepared to rewrite your code.
  4. Web pages are inconsistent - There's sometimes some manual clean up that has to happen even after you've gotten your data.

How does a web page look like?

Motivating example

rvest example

rvest is a nice R package for web-scraping

library("rvest")
read_html("http://en.wikipedia.org/wiki/Table_(information)") %>%
  html_node(".wikitable") %>% # extract first node with class wikitable
  html_table() # then convert the HTML table into a data frame
##   First name  Last name Age
## 1       Tinu   Elejogun  15
## 2      Luisa    Tebbutt  15
## 3       Lily  McGarrett  16
## 4 Olatunkboh   Chijiaku  22
## 5   Adrienne   Anthoula  22
## 6     Axelia Athanasios  22
## 7  Jon-Kabat       Zinn  22

Note: html_table only works on 'nicely' formatted HTML tables.

This is a nice format? Really? Yes, really. It's the format used to render tables on webpages.

<table class="wikitable">
  <tr>
    <th>First name</th>
    <th>Last name</th>
    <th>Age</th>
  </tr>
  <tr>
    <td>Bielat</td>
    <td>Adamczak</td>
    <td>24</td>
  </tr>
  <tr>
    <td>Blaszczyk</td>
    <td>Kostrzewski</td>
    <td>25</td>
  </tr>
  <tr>
    <td>Olatunkboh</td>
    <td>Chijiaku</td>
    <td>22</td>
  </tr>
</table> 

We're rarely that lucky - the data we want is not often in a <table> format

Luckily, selectorgadget can help

Selectorgadget is a Chrome browser extension for quickly extracting desired parts of an HTML page.

With some user feedback, the gadget find out the CSS selector that returns the highlighted page elements.

Let's give it a shot on Jyllands Posten's web page

Scraping example

Scraping Jyllands Posten in rvest

Assume we want to extract the headlines

  • fire up Selectorgadget
  • find the correct selector
    • css selector: .header
    • want to use xpath? look at the XPATH tool: Chrome extension "Xpath Helper" by Adam Sadovsky

css.selector = ".artTitle a"
link = "http://jyllands-posten.dk/"

jp.data = read_html(link) %>% 
  html_nodes(css = css.selector) %>% 
  html_text()
jp.data
##   [1] "\r\n\t\t\t\tHektiske måneder i dansk politik har ikke rykket vælgerne "                                 
##   [2] "\r\n\t\t\t\tJoe Biden stiller ikke op til præsidentvalget "                                             
##   [3] "\r\n\t\t\t\tForsvarer: ”Der blev pludselig meget travlt ved håndvasken på Rigshospitalet” "             
##   [4] "\r\n\t\t\t\tNye oplysninger i sag om død, britisk journalist i lufthavn "                               
##   [5] "\r\n\t\t\t\tPigen, der blev spærret inde af sin far i 11 år - lænket til en toiletstol "                
##   [6] "\r\n\t\t\t\tJordemødre: Vi kan ikke gøre vores arbejde ordentligt "                                     
##   [7] "\r\n\t\t\t\tFleksrenten styrer mod bundrekord - én type låntagere kan juble mest "                      
##   [8] "\r\n\t\t\t\tSådan fik Alexander Danmarks mest fulgte Instagram-profil "                                 
##   [9] "\r\n\t\t\t\tEDC: Nyt håndværkerfradrag rammer ældre boligejere "                                        
##  [10] "\r\n\t\t\t\tKronik: Udflytningen er håbløs - institutionerne vil vende tilbage til København "          
##  [11] "\r\n\t\t\t\tEn bunke reservedele er blevet til Danmarks nye \"Air Force One\" "                         
##  [12] "\r\n\t\t\t\t\"Tilbage til fremtiden\": se 26 års udvikling "                                            
##  [13] "\r\n\t\t\t\tSe den nye Star Wars-trailer "                                                              
##  [14] "\r\n\t\t\t\tNorge undrer sig: Hvorfor kommer asylansøgerne cyklende til os fra Rusland? "               
##  [15] "\r\n\t\t\t\tSex, tudeture og Beckham-klon er vejen frem "                                               
##  [16] "\r\n\t\t\t\tForsvarer: Skurken er Rigshospitalet, ikke min klient "                                     
##  [17] "\r\n\t\t\t\tUdsolgt Sverige-kamp: DBU politianmelder sortbørshajer "                                    
##  [18] "\r\n\t\t\t\tSå billig vil benzinen blive i den kommende tid "                                           
##  [19] "\r\n\t\t\t\tMikrobilerne er kørt agter ud "                                                             
##  [20] "\r\n\t\t\t\tAftale om at Kina skal levere atomkraft til briterne skaber bekymring for sikkerheden "     
##  [21] "\r\n\t\t\t\tMand på elcykel mistede livet i ulykke "                                                    
##  [22] "\r\n\t\t\t\tHelikopter fandt vindsurfer i Vesterhavet "                                                 
##  [23] "\r\n\t\t\t\tEfteråret kalder på en gammel ven fra 60’erne "                                             
##  [24] "\r\n\t\t\t\tSanser dyr verdenen? "                                                                      
##  [25] "\r\n\t\t\t\tSkjult budskab i Homeland fik de sociale medier i kog "                                     
##  [26] "\r\n\t\t\t\tStor analyse afslører:  Skal du have nyt tv? Så er det nu, du skal slå til "                
##  [27] "\r\n\t\t\t\tSe en vanddråbe danse i rummet "                                                            
##  [28] "\r\n\t\t\t\tMadkrig i Randers: De kæmper om gris på bordet "                                            
##  [29] "\r\n\t\t\t\tStor analyse afslører:  Skal du have nyt tv? Så er det nu, du skal slå til   "              
##  [30] "\r\n\t\t\t\tUtilfredse Apple-kunder raser over mystisk skærmfejl "                                      
##  [31] "\r\n\t\t\t\tDerfor er en hurtig gåtur et »vidundermiddel« mod sygdom "                                  
##  [32] "\r\n\t\t\t\tHjemmehjælper idømt forvaring for serie af voldtægter "                                     
##  [33] "\r\n\t\t\t\tVW stopper salg af lagerbiler "                                                             
##  [34] "\r\n\t\t\t\tLæserne: »Hvis de vil have halalkød, må de tage det med hjemmefra« "                        
##  [35] "\r\n\t\t\t\tRedaktørens liste:  Comeback fra Lyngby Porcelæn - Verdens første termostel vender tilbage "
##  [36] "\r\n\t\t\t\tVidne krævede penge for at møde op i narkosag i Aarhus "                                    
##  [37] "\r\n\t\t\t\tKronvidne mod dansker i Sydafrika dør efter nedskydning "                                   
##  [38] "\r\n\t\t\t\tSløv dansk start men store forventninger til Star Wars "                                    
##  [39] "\r\n\t\t\t\tMinister: Familier må selv om hvor meget de arbejder "                                      
##  [40] "\r\n\t\t\t\tVoxpop:  »Det, Sverige gør, er ansvarsløst, det Danmark gør, er ansvarsfuldt« "             
##  [41] "\r\n\t\t\t\tEksklusivt interview:  Derfor melder Audi sig ind i elbil-krigen nu "                       
##  [42] "\r\n\t\t\t\tEU-skattesmæk til Starbucks og Fiat "                                                       
##  [43] "\r\n\t\t\t\t»For helvede, Janis, hvorfor skulle du tage det sidste heroinfix?« "                        
##  [44] "\r\n\t\t\t\tDen største investering i Legos historie: Så omfattende er planen "                         
##  [45] "\r\n\t\t\t\tCordsen: Messerschmidt-sag kommer på det værst tænkelige tidspunkt for DF "                 
##  [46] "\r\n\t\t\t\tLeon Andreasen i selskab med Messi og Maradona "                                            
##  [47] "\r\n\t\t\t\tSådan får du råd til at blive gammel "                                                      
##  [48] "\r\n\t\t\t\tJobtjek: Hver fjerde i 30'erne søger nyt arbejde inden jul "                                
##  [49] "\r\n\t\t\t\tBoliglån med superrenter i spil - men hvilket skal man vælge? "                             
##  [50] "\r\n\t\t\t\tStarbucks og Fiat får skattesmæk på mio. af Vestager "                                      
##  [51] "\r\n\t\t\t\tPas på disse flyselskaber - de har mange forsinkelser og dårlig service "                   
##  [52] "\r\n\t\t\t\tNy paskontrol i Københavns Lufthavn: Sådan virker det "                                     
##  [53] "\r\n\t\t\t\tLille virksomhed tabte 1 mio. kr. på snedigt hackertrick "                                  
##  [54] "\r\n\t\t\t\tUng bankmedarbejder sendte milliarder til kunde ved en fejl "                               
##  [55] "\r\n\t\t\t\tSex, tudeture og Beckham-klon er vejen frem "                                               
##  [56] "\r\n\t\t\t\tSpejderhytten i millionklassen sætter ny standard for bæredygtighed "                       
##  [57] "\r\n\t\t\t\tHusker du:  Hækmotor-familiebilen, der kørte som en sportsvogn   "                          
##  [58] "\r\n\t\t\t\tJP mener: Er man racist, fordi man er bekymret for asyltilstrømningen? "                    
##  [59] "\r\n\t\t\t\tDagens tegning "                                                                            
##  [60] "\r\n\t\t\t\tKronik: Udflytningen er håbløs - institutionerne vil vende tilbage til København "          
##  [61] "\r\n\t\t\t\tForskere: Den ældste i søskendeflokken er mest intelligent "                                
##  [62] "\r\n\t\t\t\tFem fif:  Sådan får du mest muligt ud af din træning "                                      
##  [63] "\r\n\t\t\t\tSå meget må du få i julegave i år "                                                         
##  [64] "\r\n\t\t\t\t163 år gammelt skib fundet i stor skibskirkegård "                                          
##  [65] "\r\n\t\t\t\tSådan undgår presset virksomhed tissepauser og kantinebesøg "                               
##  [66] "\r\n\t\t\t\tAarhus-politikere gider ikke bilfri søndag "                                                
##  [67] "\r\n\t\t\t\tVidne krævede penge for at møde op i narkosag i Aarhus "                                    
##  [68] "\r\n\t\t\t\tRealDania donerer 6,8 mio. kr. til Søndervangen "                                           
##  [69] "\r\n\t\t\t\tBoot camp for ledige unge "                                                                 
##  [70] "\r\n\t\t\t\tSatire: Pølsefabrik:  Vi er ikke noget universitet "                                        
##  [71] "\r\n\t\t\t\tLivets gang på Borgen "                                                                     
##  [72] "\r\n\t\t\t\tMedgang & Modgang "                                                                         
##  [73] "\r\n\t\t\t\tNyt taxisystem sparer 330.000 timers kø ved Københavns Lufthavn "                           
##  [74] "\r\n\t\t\t\tI dag bliver \"Fremtiden\" til nutid "                                                      
##  [75] "\r\n\t\t\t\tFerrari lagde hårdt ud - men tabte fart "                                                   
##  [76] "\r\n\t\t\t\tNyt hus i Gellerup skal sætte standarden "                                                  
##  [77] "\r\n\t\t\t\tTesla X med flyvedøre klarer 0-100 km/t på 3,2 sekunder "                                   
##  [78] "\r\n\t\t\t\tFoto:  Krigen mod kokain i Peru "                                                           
##  [79] "\r\n\t\t\t\tFoto:  Døgnets bedste fotos: Lyskunst i Tyrkiet "                                           
##  [80] "\r\n\t\t\t\tFoto:  Døgnets bedste fotos: Nej, du må ikke spille guitar på lørdag "                      
##  [81] "\r\n\t\t\t\tSmæk til europæiske banker på positiv børsdag "                                             
##  [82] "\r\n\t\t\t\tMarkedsuro bekymrer ikke Nordea-chef "                                                      
##  [83] "\r\n\t\t\t\tRegnskab: Nye indskud giver præmievækst i Nordea Liv "                                      
##  [84] "\r\n\t\t\t\tChristian Clausen frygter effekt af negative renter "                                       
##  [85] "\r\n\t\t\t\tChr. Hansen er klar til at udvide medicinsatsning "                                         
##  [86] "\r\n\t\t\t\tJ&J melder sig ind i hepatitis-kampen "                                                     
##  [87] "\r\n\t\t\t\tDanske Regioner: Godt, at vi formåede at holde udgiftsstigningen nede "                     
##  [88] "\r\n\t\t\t\tAnklager kræver overlæge idømt mindst to års ubetinget fængsel "                            
##  [89] "\r\n\t\t\t\tAmerikanske olielagre steg mere end ventet "                                                
##  [90] "\r\n\t\t\t\tKapitalfond stejler over DSV's købstilbud "                                                 
##  [91] "\r\n\t\t\t\tOlieindustrien: \"Alle kommer til at lide\" "                                               
##  [92] "\r\n\t\t\t\tBlue MBA sætter ny rekord i antal studerende "                                              
##  [93] "\r\n\t\t\t\tGrarup: Skylark skal lave tv for nicher og nationer "                                       
##  [94] "\r\n\t\t\t\tTV 2 Nyhederne finder ny grafikchef i DR "                                                  
##  [95] "\r\n\t\t\t\tOpgør med rettighedsadvokat støder på forsinkelse "                                         
##  [96] "\r\n\t\t\t\tPearson-aktien falder til bunds efter nedjustering "                                        
##  [97] "\r\n\t\t\t\tAmerikanske olielagre steg mere end ventet i sidste uge "                                   
##  [98] "\r\n\t\t\t\tEl Niño blæser ikke Iberdrola omkuld "                                                      
##  [99] "\r\n\t\t\t\tKina på vej ind i britisk havvind "                                                         
## [100] "\r\n\t\t\t\tOlieindustrien: \"Alle kommer til at lide\" "                                               
## [101] "\r\n\t\t\t\tSmå kaffebarer glæder sig over skattesmæk til Starbucks "                                   
## [102] "\r\n\t\t\t\tChr. Hansen blev den store aktievinder "                                                    
## [103] "\r\n\t\t\t\tLandbrugsorganisation mister sin direktør "                                                 
## [104] "\r\n\t\t\t\tNyt marked: Bakteriefirma vil forlænge levetid på laks "

Garbage

Notice that there are still some garbage characters in the scraped text

head(jp.data, 5)
## [1] "\r\n\t\t\t\tHektiske måneder i dansk politik har ikke rykket vælgerne "                    
## [2] "\r\n\t\t\t\tJoe Biden stiller ikke op til præsidentvalget "                                
## [3] "\r\n\t\t\t\tForsvarer: ”Der blev pludselig meget travlt ved håndvasken på Rigshospitalet” "
## [4] "\r\n\t\t\t\tNye oplysninger i sag om død, britisk journalist i lufthavn "                  
## [5] "\r\n\t\t\t\tPigen, der blev spærret inde af sin far i 11 år - lænket til en toiletstol "

So we need our string processing skills to clean the scraped data

library("stringr")
jp.data.clean = jp.data %>% 
  str_replace_all(pattern = "\\n" , replacement = " ") %>%
  str_trim()

head(jp.data.clean, 15)
##  [1] "Hektiske måneder i dansk politik har ikke rykket vælgerne"                       
##  [2] "Joe Biden stiller ikke op til præsidentvalget"                                   
##  [3] "Forsvarer: ”Der blev pludselig meget travlt ved håndvasken på Rigshospitalet”"   
##  [4] "Nye oplysninger i sag om død, britisk journalist i lufthavn"                     
##  [5] "Pigen, der blev spærret inde af sin far i 11 år - lænket til en toiletstol"      
##  [6] "Jordemødre: Vi kan ikke gøre vores arbejde ordentligt"                           
##  [7] "Fleksrenten styrer mod bundrekord - én type låntagere kan juble mest"            
##  [8] "Sådan fik Alexander Danmarks mest fulgte Instagram-profil"                       
##  [9] "EDC: Nyt håndværkerfradrag rammer ældre boligejere"                              
## [10] "Kronik: Udflytningen er håbløs - institutionerne vil vende tilbage til København"
## [11] "En bunke reservedele er blevet til Danmarks nye \"Air Force One\""               
## [12] "\"Tilbage til fremtiden\": se 26 års udvikling"                                  
## [13] "Se den nye Star Wars-trailer"                                                    
## [14] "Norge undrer sig: Hvorfor kommer asylansøgerne cyklende til os fra Rusland?"     
## [15] "Sex, tudeture og Beckham-klon er vejen frem"

Links

Looping through collection of links

Loops in R

for(i in 1:5){
  print(paste("I'm now at number", i, sep = " "))
}
## [1] "I'm now at number 1"
## [1] "I'm now at number 2"
## [1] "I'm now at number 3"
## [1] "I'm now at number 4"
## [1] "I'm now at number 5"

We need a function to grab all the text at JP

Functions are easy to write (but be careful)

my.first.function = function(number){
  return(number + 5)
}
my.first.function(10)
## [1] 15
my.first.function("hello")
## Error in number + 5: non-numeric argument to binary operator

my.first.function = function(number){
  if(!is.numeric(number)){
      stop("your 'number' is not numeric")
  }
  else{
    return(number + 5)
  }
}
my.first.function(10)
## [1] 15
my.first.function("hello")
## Error in my.first.function("hello"): your 'number' is not numeric

my.first.function = function(number){
  if(!is.numeric(number)){
      number = "you did not provide a number"
      return(print(number))
  }
  else{
    return(number + 5)
  }
}
my.first.function(10)
## [1] 15
my.first.function("hello")
## [1] "you did not provide a number"

Returning to our example

Let's look at the first link

jp.links[1]
## [1] "http://jyllands-posten.dk/politik/ECE8141105/Hektisk-politisk-sommer-har-ikke-rykket-vælgerne/"

There might be an encoding error, see actual R output

Let's go to that page

Grab info from first link

first.link.text.collapsed = paste(first.link.text, collapse = "")
head(first.link.text.collapsed, 3)
## [1] "126 dage er gået siden Helle Thorning-Schmidt og Socialdemokraterne måtte overdrage nøglerne til Statsministeriet til Lars Løkke Rasmussen og Venstre.Og selvom det har været 126 dage med relativ heftig aktivitet i Folketinget, en grænseoverskridende flygtningekrise, Carl Holsts pludselige ministerafgang og store regeringsudspil såsom finanslovsforslag, kontanthjælpsloft og udflytning af statslige arbejdspladser, ja, så har partiernes vælgertilslutning stort set ikke rykket sig siden valgdagen.Det viser en dugfrisk meningsmåling, som instituttet Wilke har foretaget for Jyllands-Posten.I forhold til valgresultatet fra juni går Venstre og Socialdemokraterne hver især ét mandat tilbage, mens Enhedslisten som eneste parti står til at gå to mandater frem til i alt 16 sæder i Folketinget. Alle andre partiers mandattal er uændrede i forhold til valgrestultatet.De få udslag i målingen skal ydermere tages med forbehold, da de alle ligger inden for den statistiske usikkerhed. Med andre ord viser målingen reelt status quo i dansk politik.Med 18,9 procent står Venstre fortsat til den laveste vælgeropbakning i årevis, efter valgresultatet på på 19,5 procent. Ikke engang under Lars Løkke Rasmussens personlige bilagskrise i 2014 dykkede partiet så langt ned i målingerne.»Som man siger på godt jysk: Det ku' ha' været møj' værre,« siger han og peger på, at den smalle Venstre-regering har fremlagt et stramt finanslovsforslag med besparelser på blandt andet udviklingsbistanden og forskningsmidlerne, og at hele flygtningesituationen, hvor tusindvis af flygtninge og migranter er kommet til Danmark, har sat regeringen på prøve.»Det har været en periode med udfordringer og svære beslutninger. Alligevel har vi nogenlunde den samme opbakning som ved valget, og det er jeg meget godt tilfreds med,« siger han.Socialdemokraterne bevarer med 26,3 pct. af stemmerne positionen som Folketingets største parti efterfulgt af Dansk Folkeparti med 20,9 pct.Sammenligner man blokkene er der stadig blåt flertal med fordelingen 89 mandater bag Løkke som statsminister og 86 mandater bag Socialdemokraternes formand Mette Frederiksen.Blå blok opnår 51,0 pct. af stemmerne, hvilket er en tilbagegang på 1,3 procentpoint i forhold til valget. I princippet ville de fire nordatlantiske mandater i Folketinget - som alle støtter rød blok - dermed kunne tippe flertallet i Folketinget, men det er for usikkert til at kunne sige med sikkerhed.»Jeg kan konstatere, at vi stadig har et blåt flertal, og at der ud af det blå flertal er ét parti, der er villig til at tage regeringsansvar - det tager vi gerne på os,« siger Jakob Ellemann-Jensen, men henvisning til, af DF valgte ikke at gå med i Løkkes regering.Men kan Venstre være tilfredse med 18,9 procent af stemmerne?»Målet skal da altid være at blive større, end vi er. Men med regeringsansvaret følger også nogle prygl. Og dem synes jeg egentlig ikke har været så slemme, som man kunne have troet,« lyder det fra Jakob Ellemann-Jensen.\r\n\t\t\t\t•\r\n\t\t\t\tHer er de meningsmålinger, der var længst fra og tættest på\r\n\t\tEfter valget 18. juni stod det klart, at en af valgkampens store tabere var meningsmålingerne, der undervejs havde strittet i alle mulige retninger, og for flere partiers vegne viste sig at ramme skævt. Det gjaldt ikke mindst Wilkes sidste måling for Jyllands-Posten, som havde en samlet fejlmargin på 5,9 procentpoint i forhold til valgresultatet.Siden valget har Jyllands-Posten derfor ikke offentliggjort politiske målinger fra Wilke. Dagens udgave er den første.Og for at sikre større præcision og troværdighed har Wilke forbedret sin målingsmetode på fem konkrete punkter, som Jyllands-Postens chefredaktør Pierre Collignon præsenterer her.Blandt andet vil Jyllands-Posten fremover bringe færre men grundigere målinger, hvor antallet af respondenter fordobles fra ca. 1.000 til ca. 2.000 personer pr. måling."

While we're at it…

Let's also grab the author of the article

read_html(first.link, encoding = "UTF-8") %>% 
  html_nodes(".bylineAuthorName span") %>% 
  html_text()
## [1] "STEEN A. JØRGENSSEN"

Turning it into a function

We need a function that for each new link will return the text we're interested in

scrape_jp = function(link){
  my.link = read_html(link, encoding = "UTF-8")
  my.link.text = my.link %>% 
    html_nodes("#articleText p") %>% html_text() %>% 
    paste(collapse = "")
  my.link.author = my.link %>% 
    html_nodes(".bylineAuthorName span") %>% html_text()
  return(cbind( my.link.author, link, my.link.text ))
}

scrape_jp(first.link)
##      my.link.author       
## [1,] "STEEN A. JØRGENSSEN"
##      link                                                                                            
## [1,] "http://jyllands-posten.dk/politik/ECE8141105/Hektisk-politisk-sommer-har-ikke-rykket-vælgerne/"
##      my.link.text                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               
## [1,] "126 dage er gået siden Helle Thorning-Schmidt og Socialdemokraterne måtte overdrage nøglerne til Statsministeriet til Lars Løkke Rasmussen og Venstre.Og selvom det har været 126 dage med relativ heftig aktivitet i Folketinget, en grænseoverskridende flygtningekrise, Carl Holsts pludselige ministerafgang og store regeringsudspil såsom finanslovsforslag, kontanthjælpsloft og udflytning af statslige arbejdspladser, ja, så har partiernes vælgertilslutning stort set ikke rykket sig siden valgdagen.Det viser en dugfrisk meningsmåling, som instituttet Wilke har foretaget for Jyllands-Posten.I forhold til valgresultatet fra juni går Venstre og Socialdemokraterne hver især ét mandat tilbage, mens Enhedslisten som eneste parti står til at gå to mandater frem til i alt 16 sæder i Folketinget. Alle andre partiers mandattal er uændrede i forhold til valgrestultatet.De få udslag i målingen skal ydermere tages med forbehold, da de alle ligger inden for den statistiske usikkerhed. Med andre ord viser målingen reelt status quo i dansk politik.Med 18,9 procent står Venstre fortsat til den laveste vælgeropbakning i årevis, efter valgresultatet på på 19,5 procent. Ikke engang under Lars Løkke Rasmussens personlige bilagskrise i 2014 dykkede partiet så langt ned i målingerne.»Som man siger på godt jysk: Det ku' ha' været møj' værre,« siger han og peger på, at den smalle Venstre-regering har fremlagt et stramt finanslovsforslag med besparelser på blandt andet udviklingsbistanden og forskningsmidlerne, og at hele flygtningesituationen, hvor tusindvis af flygtninge og migranter er kommet til Danmark, har sat regeringen på prøve.»Det har været en periode med udfordringer og svære beslutninger. Alligevel har vi nogenlunde den samme opbakning som ved valget, og det er jeg meget godt tilfreds med,« siger han.Socialdemokraterne bevarer med 26,3 pct. af stemmerne positionen som Folketingets største parti efterfulgt af Dansk Folkeparti med 20,9 pct.Sammenligner man blokkene er der stadig blåt flertal med fordelingen 89 mandater bag Løkke som statsminister og 86 mandater bag Socialdemokraternes formand Mette Frederiksen.Blå blok opnår 51,0 pct. af stemmerne, hvilket er en tilbagegang på 1,3 procentpoint i forhold til valget. I princippet ville de fire nordatlantiske mandater i Folketinget - som alle støtter rød blok - dermed kunne tippe flertallet i Folketinget, men det er for usikkert til at kunne sige med sikkerhed.»Jeg kan konstatere, at vi stadig har et blåt flertal, og at der ud af det blå flertal er ét parti, der er villig til at tage regeringsansvar - det tager vi gerne på os,« siger Jakob Ellemann-Jensen, men henvisning til, af DF valgte ikke at gå med i Løkkes regering.Men kan Venstre være tilfredse med 18,9 procent af stemmerne?»Målet skal da altid være at blive større, end vi er. Men med regeringsansvaret følger også nogle prygl. Og dem synes jeg egentlig ikke har været så slemme, som man kunne have troet,« lyder det fra Jakob Ellemann-Jensen.\r\n\t\t\t\t•\r\n\t\t\t\tHer er de meningsmålinger, der var længst fra og tættest på\r\n\t\tEfter valget 18. juni stod det klart, at en af valgkampens store tabere var meningsmålingerne, der undervejs havde strittet i alle mulige retninger, og for flere partiers vegne viste sig at ramme skævt. Det gjaldt ikke mindst Wilkes sidste måling for Jyllands-Posten, som havde en samlet fejlmargin på 5,9 procentpoint i forhold til valgresultatet.Siden valget har Jyllands-Posten derfor ikke offentliggjort politiske målinger fra Wilke. Dagens udgave er den første.Og for at sikre større præcision og troværdighed har Wilke forbedret sin målingsmetode på fem konkrete punkter, som Jyllands-Postens chefredaktør Pierre Collignon præsenterer her.Blandt andet vil Jyllands-Posten fremover bringe færre men grundigere målinger, hvor antallet af respondenter fordobles fra ca. 1.000 til ca. 2.000 personer pr. måling."

Now we can loop through the links and grab the data

We store the data in a list that we later turn into a data frame

my.jp.data = list() # initialize empty list
for (i in jp.links[1:5]){
  print(paste("processing", i, sep = " "))
  my.jp.data[[i]] = scrape_jp(i)
  # waiting one second between hits
  Sys.sleep(1)
  cat(" done!\n")
}
## [1] "processing http://jyllands-posten.dk/politik/ECE8141105/Hektisk-politisk-sommer-har-ikke-rykket-vælgerne/"
##  done!
## [1] "processing http://jyllands-posten.dk/international/usa/ECE8141738/Joe-Biden-stiller-ikke-op-til-præsidentvalget/"
##  done!
## [1] "processing http://jyllands-posten.dk/indland/politiretsvaesen/ECE8141201/Forsvarer-”Der-blev-pludselig-meget-travlt-ved-håndvasken-på-Rigshospitalet”/"
##  done!
## [1] "processing http://jyllands-posten.dk/international/ECE8140740/Nye-oplysninger-i-sagen-om-den-britiske-journalist-Jacqueline-Sutton-som-døde-i-lufthavn/"
##  done!
## [1] "processing http://www.jyllands-posten.dk/protected/premium/indblik/Kultur/ECE8126072/Pigen-der-blev-spærret-inde-af-sin-far-i-11-år---lænket-til-en-toiletstol/"
##  done!

transforming it into a data.frame

library("plyr")
df = ldply(my.jp.data)
df$article = jp.data.clean[1:5]
head(df, 2)
##                                                                                                     .id
## 1        http://jyllands-posten.dk/politik/ECE8141105/Hektisk-politisk-sommer-har-ikke-rykket-vælgerne/
## 2 http://jyllands-posten.dk/international/usa/ECE8141738/Joe-Biden-stiller-ikke-op-til-præsidentvalget/
##                                           my.link.author
## 1                                    STEEN A. JØRGENSSEN
## 2 JOHANNES KAAS FALLESEN, Jyllands-Postens korrespondent
##                                                                                                    link
## 1        http://jyllands-posten.dk/politik/ECE8141105/Hektisk-politisk-sommer-har-ikke-rykket-vælgerne/
## 2 http://jyllands-posten.dk/international/usa/ECE8141738/Joe-Biden-stiller-ikke-op-til-præsidentvalget/
##                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                my.link.text
## 1 126 dage er gået siden Helle Thorning-Schmidt og Socialdemokraterne måtte overdrage nøglerne til Statsministeriet til Lars Løkke Rasmussen og Venstre.Og selvom det har været 126 dage med relativ heftig aktivitet i Folketinget, en grænseoverskridende flygtningekrise, Carl Holsts pludselige ministerafgang og store regeringsudspil såsom finanslovsforslag, kontanthjælpsloft og udflytning af statslige arbejdspladser, ja, så har partiernes vælgertilslutning stort set ikke rykket sig siden valgdagen.Det viser en dugfrisk meningsmåling, som instituttet Wilke har foretaget for Jyllands-Posten.I forhold til valgresultatet fra juni går Venstre og Socialdemokraterne hver især ét mandat tilbage, mens Enhedslisten som eneste parti står til at gå to mandater frem til i alt 16 sæder i Folketinget. Alle andre partiers mandattal er uændrede i forhold til valgrestultatet.De få udslag i målingen skal ydermere tages med forbehold, da de alle ligger inden for den statistiske usikkerhed. Med andre ord viser målingen reelt status quo i dansk politik.Med 18,9 procent står Venstre fortsat til den laveste vælgeropbakning i årevis, efter valgresultatet på på 19,5 procent. Ikke engang under Lars Løkke Rasmussens personlige bilagskrise i 2014 dykkede partiet så langt ned i målingerne.»Som man siger på godt jysk: Det ku' ha' været møj' værre,« siger han og peger på, at den smalle Venstre-regering har fremlagt et stramt finanslovsforslag med besparelser på blandt andet udviklingsbistanden og forskningsmidlerne, og at hele flygtningesituationen, hvor tusindvis af flygtninge og migranter er kommet til Danmark, har sat regeringen på prøve.»Det har været en periode med udfordringer og svære beslutninger. Alligevel har vi nogenlunde den samme opbakning som ved valget, og det er jeg meget godt tilfreds med,« siger han.Socialdemokraterne bevarer med 26,3 pct. af stemmerne positionen som Folketingets største parti efterfulgt af Dansk Folkeparti med 20,9 pct.Sammenligner man blokkene er der stadig blåt flertal med fordelingen 89 mandater bag Løkke som statsminister og 86 mandater bag Socialdemokraternes formand Mette Frederiksen.Blå blok opnår 51,0 pct. af stemmerne, hvilket er en tilbagegang på 1,3 procentpoint i forhold til valget. I princippet ville de fire nordatlantiske mandater i Folketinget - som alle støtter rød blok - dermed kunne tippe flertallet i Folketinget, men det er for usikkert til at kunne sige med sikkerhed.»Jeg kan konstatere, at vi stadig har et blåt flertal, og at der ud af det blå flertal er ét parti, der er villig til at tage regeringsansvar - det tager vi gerne på os,« siger Jakob Ellemann-Jensen, men henvisning til, af DF valgte ikke at gå med i Løkkes regering.Men kan Venstre være tilfredse med 18,9 procent af stemmerne?»Målet skal da altid være at blive større, end vi er. Men med regeringsansvaret følger også nogle prygl. Og dem synes jeg egentlig ikke har været så slemme, som man kunne have troet,« lyder det fra Jakob Ellemann-Jensen.\r\n\t\t\t\t•\r\n\t\t\t\tHer er de meningsmålinger, der var længst fra og tættest på\r\n\t\tEfter valget 18. juni stod det klart, at en af valgkampens store tabere var meningsmålingerne, der undervejs havde strittet i alle mulige retninger, og for flere partiers vegne viste sig at ramme skævt. Det gjaldt ikke mindst Wilkes sidste måling for Jyllands-Posten, som havde en samlet fejlmargin på 5,9 procentpoint i forhold til valgresultatet.Siden valget har Jyllands-Posten derfor ikke offentliggjort politiske målinger fra Wilke. Dagens udgave er den første.Og for at sikre større præcision og troværdighed har Wilke forbedret sin målingsmetode på fem konkrete punkter, som Jyllands-Postens chefredaktør Pierre Collignon præsenterer her.Blandt andet vil Jyllands-Posten fremover bringe færre men grundigere målinger, hvor antallet af respondenter fordobles fra ca. 1.000 til ca. 2.000 personer pr. måling.
## 2                                                                                                                                                                                                                                                                Los AngelesDer blev gjort en ende på flere måneders spekulationer, da Det Hvide Hus i al hast indkaldte til pressemøde tidligt onsdag aften dansk tid.Den amerikanske vicepræsident, Joe Biden, vil ikke forsøge at blive valgt som Demokraternes præsidentkandidat til valget i november 2016.Joe Biden har trukket sin beslutning længe, da hans familie har sørget over tabet af vicepræsidentens søn Beau Biden i foråret.»Jeg har flere gange sagt, at denne proces kunne gøre, at det i sidste ende ville lukke vinduet for en realistisk chance for en kampagne. Min konklusion er, at det er lukket,« sagde Joe Biden flankeret af præsident Barack Obama og konen Jill Biden.Amerikanske medier har ellers i de sidste par dage meldt, at vicepræsidenten rent faktisk havde besluttet sig for at gå efter det mest eftertragtede kontor i Det Hvide Hus. \r\n\t\t\t\t•\r\n\t\t\t\tMarkant udskiftning undervejs blandt demokratiske præsidentkandidater\r\n\t\tJoe Biden afviste på pressemødet, at beslutningen skulle have noget at gøre med, at familien havde sat foden ned og nægtet at være en del af en opslidende præsidentvalgkamp.»Jeg har hele tiden sagt, at jeg ikke kunne gøre det her, hvis ikke familien var klar. Den gode nyhed er dog, at familien har nået det punkt,« sagde Joe Biden.Vicepræsidenten fortalte, at familien nu kunne smile, når den tænkte på Beau Biden, men tiden er løbet ud for et Biden-kandidatur.»Vi er løbet tør for tid i forhold til at sætte en succesfuld valgkamp sammen. Selvom jeg ikke stiller op, kommer jeg ikke til at være stille. Jeg kommer til at tale klart og kraftigt for at få så meget indflydelse som overhovedet muligt,« sagde Joe Biden.»Partiet og vores nation vil begå en tragisk fejl, hvis vi forsøger at bevæge os væk fra eller omgøre Obama-eftermælet. Ikke alene burde demokraterne forsvare dette arbejde og beskytte det, de burde rent faktisk bruge det som valgprogram,« lød det fra Joe Biden.Det var da også ventet, at Joe Biden, hvis han valgte at stille op, ville gøre det på en platform, der i det store hele kunne betragtes som en videreførelse af det arbejde, som Barack Obama har stået for. \r\n\t\t\t\t•\r\n\t\t\t\tHårdt angreb mod Biden før afgørende beslutning \r\n\t\tPå trods af aldrig formelt at have været en del af feltet af demokratiske præsidentkandidater, så har Joe Biden alligevel formået at opretholde ganske pæne tal i meningsmålingerne. I et gennemsnit af de seneste af slagsen, foretaget af hjemmesiden realclearpolitics.com, kan vicepræsidenten mønstre 16,8 procent af stemmerne fra de demokratiske vælgere, hvilket dog er lidt over 22 procentpoint færre end favoritten, den tidligere udenrigsminister Hillary Clinton.Netop Clinton er den, der ventes at have størst gavn af Joe Bidens beslutning om ikke at stille op. I en måling foretaget for tv-stationen CNN, der blev offentliggjort mandag, steg Hillary Clintons tilslutning med 11 procentpoint, hvis man fjernede Joe Biden fra ligningen.Den tidligere udenrigsministers nærmeste rival, Vermont-senatoren Bernie Sanders, fik blot en øget tilslutning på fire procentpoint uden vicepræsidenten i feltet. \r\n\t\t\t\t•\r\n\t\t\t\tHillary Clintons forspring på sit laveste hidtil\r\n\t\tMed Bidens udmelding tegner det demokratiske kandidatfelt til at tælle i alt fire kandidater. Foruden Hillary Clinton og Bernie Sanders drejer det sig om de tidligere guvernører Martin O'Malley og Lincoln Chafee.Tirsdag valgte den tidligere senator Jim Webb at trække sig som den første fra det demokratiske felt af kandidater.De demokratiske vælgere i staten Iowa bliver de første til at stemme om partiets præsidentkandidat 1. februar 2016.
##                                                     article
## 1 Hektiske måneder i dansk politik har ikke rykket vælgerne
## 2             Joe Biden stiller ikke op til præsidentvalget

That's it.

Your turn

Exercise

  1. Go to http://www.econ.ku.dk/ansatte/vip/
  2. Create a vector of all links to the researcher's personal home page
  3. Go to each researchers page and grab their title
  4. Create a data frame of all researchers' names and title
##                        name              r.interest
## 1         Kibrom Araya Abay                 Postdoc
## 2           Steffen Altmann                  Lektor
## 3        Asger Lau Andersen                 Adjunkt
## 4         Sebastian Barfort Videnskabelig assistent
## 5    Jeanet Sinding Bentzen                 Adjunkt
## 6       Ulf Michael Bergman                  Lektor
## 7     Simon Halphen Boserup                 Postdoc
## 8  Carl-Johan Lars Dalgaard               Professor
## 9              Mette Ejrnæs               Professor
## 10      Ferran Elias Moreno                 Adjunkt
## 11       Benjamin Falkeborg                 Postdoc
## 12              Mette Foged                 Postdoc
## 13         Miriam Gensowski                 Adjunkt
## 14    Martin Gonzalez Eiras                  Lektor
## 15          Christian Groth                  Lektor

Gathering data from APIs

API

API = Application Program Interface

Many data sources have API's - largely for talking to other web interfaces

Consists of a set of methods to search, retrieve, or submit data to, a data source

We can write R code to interface with an API (lot's require authentication though)

Many packages already connect to well-known API's (we'll look at a couple today)

twitteR

twitteR is an R package which provides access to the Twitter API

streamR provides access to Twitters streaming API

Create an app here

library("twitteR")
consumer_key = 'your key'
consumer_secret = 'your secret'
access_token = 'your access token'
access_secret = 'your access secret'

setup_twitter_oauth(consumer_key,
                    consumer_secret,
                    access_token,
                    access_secret)

searchTwitter("#dkpol", n=500)

NYT API

rtimes is a collection of functions to search and acquire data from various New York Times APIs.

Register for your own API keys here

library("rtimes")
out = as_search(q = "bailout", 
                begin_date = "20081001", 
                end_date = '20081201',
                 key = "XXX")
out$data[1:2]

Statistics Denmark API

This R package connects to the StatBank API from Statistics Denmark.

library("devtools")
install_github("rOpenGov/dkstat")

Let's you programatically work with Statistics Denmark data

library("dkstat")
dst_search(string = "bnp", field = "text")
##         id
## 405 CFABNP
## 907   NAN1
## 911  NAHL2
## 912  NAHO2
## 913 NAHD21
## 961   NKN1
## 965  NKHO2
## 979   NRHP
##                                                                  text
## 405                                        FoU udgifter i pct. af BNP
## 907 Forsyningsbalance, Bruttonationalprodukt (BNP), beskæftigelse mv.
## 911         1-2.1.1 Produktion, BNP og indkomstdannelse (hovedposter)
## 912            1-2.1.1 Produktion, BNP og indkomstdannelse (oversigt)
## 913                                  1 Produktion og BNP (detaljeret)
## 961 Forsyningsbalance, Bruttonationalprodukt (BNP), beskæftigelse mv.
## 965                       1-2.1.1 Produktion, BNP og indkomstdannelse
## 979                       1-2.1.1 Produktion, BNP og indkomstdannelse
##                                       unit             updated firstPeriod
## 405 Procent af bruttonationalprodukt (BNP) 2015-01-30T09:00:00        1997
## 907                                      - 2015-06-30T09:00:00        1966
## 911                               Mio. kr. 2015-06-30T09:00:00        1966
## 912                               Mio. kr. 2015-06-30T09:00:00        1995
## 913                               Mio. kr. 2014-11-06T09:00:00        1995
## 961                                      - 2015-09-30T09:00:00      1990K1
## 965                               Mio. kr. 2015-09-30T09:00:00      1990K1
## 979                                      - 2014-12-16T09:00:00        1993
##     latestPeriod active                                     variables
## 405         2013   TRUE                               pct af BNP, tid
## 907         2014   TRUE                   transaktion, prisenhed, tid
## 911         2014   TRUE                   transaktion, prisenhed, tid
## 912         2014   TRUE                   transaktion, prisenhed, tid
## 913         2013   TRUE                   transaktion, prisenhed, tid
## 961       2015K2   TRUE transaktion, prisenhed, sæsonkorrigering, tid
## 965       2015K2   TRUE transaktion, prisenhed, sæsonkorrigering, tid
## 979         2013   TRUE           område, transaktion, prisenhed, tid

aulaar = dst_get_data(table = "AULAAR", KØN = "Total", 
                       PERPCT = "Per cent of the labour force", 
                       Tid = 2013,
                       lang = "en")
aulaar
##     KØN                       PERPCT        TID value
## 1 Total Per cent of the labour force 2013-01-01   4.4