2016-07-08 41 views
0

我是R新手,我遇到了一个我无法解决的问题。我想在选区一级摘取瑞典选举数据。它们被构造为可使用此代码在这里http://www.val.se/val/val2014/slutresultat/K/valdistrikt/25/82/0134/personroster.htmlR - 从数据框中获取html地址到rvest

我得到我想要的数据发现:

library(rvest) 
district.data <- read_html("http://www.val.se/val/val2014/slutresultat/K/kommun/25/82/0134/personroster.html") 
prost <- district.data %>% 
html_nodes("table") %>% 
.[[2]] %>% 
html_table() 

但是,这仅仅是一个区出6,227个区。这些区域由html地址标识。在上面提到的网站中,它被标识为“25/82/0134”。我可以在这里找到http://www.val.se/val/val2014/statistik/2014_riksdagsval_per_valdistrikt.skv

各区的身份和我读到这个分号通过使用此代码分离文件到R:

valres <-read_csv2("http://www.val.se/val/val2014/statistik/2014_riksdagsval_per_valdistrikt.skv")

(作为一个方面说明,我怎么能改编码使瑞典字母(例如å,ä,ö)正确导入?我设法使用read.csv并指定encoding='utf-8'而不是用read_csv)

在此数据框中,列LAN,KOM和VALDIST给出该地区的身份s(注意,VALDIST有时只有2个字符)。因此,地址具有以下结构http://www.val.se/val/val2014/slutresultat/K/kommun/LAN/KOM/VALDIST /personroster.html

所以,我想用相结合各行中得到区的身份,刮信息进入R,添加一个具有区域标识的列(即LAN,KOM和VALDIST合并为一个字符串),并在所有6,227个区域中添加,并将来自每个区域的信息附加到单个数据框中。我假设我需要使用某种循环或其中一些应用函数来遍历数据框架,但我还没有弄清楚它是如何实现的。

更新: 在我在下面的答案中收到(谢谢!)的帮助后,现在的代码如下。我剩下的问题是,我想为每个网站添加区域标识(即paste0(LAN, KOM, VALDIST)),这些网站被截取到最终数据框中的列。有人能帮助我完成最后一步吗?

# Read the indentities of the districts (w Swedish letters) 
districts_url <- "http://www.val.se/val/val2014/statistik/2014_riksdagsval_per_valdistrikt.skv" 
valres <- read_csv2(districts_url, locale=locale("sv",encoding="ISO-8859-1", asciify=FALSE)) 

# Add a variabel to separate the two types of electoral districts 
valres$typ <- "valdistrikt" 
valres$typ [nchar(small_valres$VALDIST) == 2] <- "onsdagsdistrikt" 

# Create a vector w all the web addresses to the district data 
base_url <- "http://www.val.se/val/val2014/slutresultat/K/%s/%s/%s/%s/personroster.html" 
urls <- with(small_valres, sprintf(base_url, typ, LAN, KOM, VALDIST)) 

# Scrape the data 
pb <- progress_estimated(length(urls)) 
map_df(urls, function(x) { 

    pb$tick()$print() 
    # Maybe add Sys.sleep(1) 
    read_html(x) %>% 
     html_nodes("table") %>% 
     .[[2]] %>% 
     html_table() 
}) -> df 

任何帮助将不胜感激!

一切顺利, 理查德

回答

1

您可以使用sprintf()做位置替换,然后用purrr::map_df()遍历URL的矢量和产生的数据帧:

library(rvest) 
library(readr) 
library(purrr) 
library(dplyr) 

districts_url <- "http://www.val.se/val/val2014/statistik/2014_riksdagsval_per_valdistrikt.skv" 
valres <- read_csv2(districts_url, locale=locale("sv",encoding="UTF-8", asciify=FALSE)) 

base_url <- "http://www.val.se/val/val2014/slutresultat/K/valdistrikt/%s/%s/%s/personroster.html" 

urls <- with(valres, sprintf(base_url, LAN, KOM, VALDIST)) 

pb <- progress_estimated(length(urls)) 
map_df(urls, function(x) { 

    pb$tick()$print() 

    read_html(x) %>% 
    html_nodes("table") %>% 
    .[[2]] %>% 
    html_table() 

}) -> df 

然而,你应该添加一个随机延迟,以避免被阻止作为机器人,并应该看看包装read_html()purrr::safely()因为不是所有这些LAN/KOM/VALDIST组合都是有效的URL(至少在我的测试中)。

该代码还提供了一个进度条,因为它需要一段时间(在适度体面的连接上每小时一小时)。

+0

谢谢你的回答!只有几个后续问题:1)如何添加随机延迟? 2)我注意到,即使编码为“UTF-8”,字符也不能正确导入,我可以在编码中指定ISO代码吗?对于所有问题抱歉,R对我来说是非常新的。 – user2245655

+0

我认为我得到的错误信息是“open.connection(x,”rb“)中的错误:HTTP错误404。”,是因为没有延迟。对不起,还有一个问题 - 我如何将创建的数据框中的区域(即LAN,KOM和VALDIST合并为一个字符串变量)的标识添加为附加列? – user2245655

+0

对不起,错误消息似乎是由于一些html地址无效的事实,正如你所提到的。 VALDIST只有两个字符的地址是不同的。我设法通过添加'valres $ typ < - “valdistrikt”' 'valres $ typ [nchar(small_valres $ VALDIST)== 2] < - “onsdagsdistrikt”'来解决这个问题。 'base_url < - “http://www.val.se/val/val2014/slutresultat/K/%s/%s/%s/%s/personroster.html”''urls < - with(valres,sprintf( base_url,typ,LAN,KOM,VALDIST))''。但是我仍然不知道如何添加一个带分区id的列,即LAN,KOM和VALDIST。 – user2245655