2017-04-04 48 views
0

有没有人知道by_rowrowwise之间有什么区别?我试图抓取3个简单的网站,而且我似乎无法得到任何一种工作方式,所以我不确定我是否仅仅使用了purr/dplyr错误。by_row vs rowwise iteration

数据:

structure(list(beer_brewerid = c("8481", "3228", "10325"), link = 
c("https://www.ratebeer.com/beer/8481/", "https://www.ratebeer.com/beer/3228/", "https://www.ratebeer.com/beer/10325/"), scrapedname = c("", "", "")), .Names = c("beer_brewerid", "link", "scrapedname"), row.names = c(NA, 3L), class = "data.frame") 

对于每一个URL(或行),我想用下面的函数来刮的网页:

dplyr approach: 
    table %>% 
     rowwise() %>% 
     read_html() %>% 
     extract2(2) %>% 
     html_nodes("#_brand4 span") %>% 
     html_text() 

发出呼噜声的方法:

#Apply function to each row 
table %>% 
    by_row(..f = parserows(), collate = c("rows"), .to = "scrapedname") 

#Takes in row 
parserows = function(){ 
     read_html() %>% 
     extract2(., 2) %>% 
     html_nodes("#_brand4 span") %>% 
     html_text() 
} 

purr的方法中,我不断收到一个错误,其中x缺失而没有默认值。该值不应该来自行号?否则,我会写一个for循环,指定行号所在的索引。

使用这种magrittr管道,我不断收到超时错误与我code.So:

  1. 如何避免超时错误使用的呼噜声/ dplyr超过迭代我DF所有的元素是什么时候?如果是这样,我应该看看使用trycatch还是某种错误处理机制来捕获错误发生时的错误?

  2. rowwise/by_row真的是这个任务吗?我认为这些函数是为了对一行中的每个元素进行迭代,这不正是我想要解决的问题。谢谢。

    output = table$link %>% 
    extract() %>% 
    map(read_html) %>% 
    html_nodes(row,"#_brand4 span") %>% 
    html_text(row) 
    
+0

我把你的链接作为一个载体,映射在他们:'my_dat $链接%>% 地图(read_html)%>%...' –

+0

唯一的问题是,当我有很多链接我要刮,我不断收到超时错误。查看更新的代码。 – petergensler

+0

看看'purrr :: safely'和'purrr :: transpose'。 –

回答

3

这里是@Thomas K公司的建议可能是什么样子:

第一只purrr

library(purrr) 
library(dplyr) 
library(httr) 
library(xml2) 
library(rvest) 

table$link %>% 
    purrr::set_names() %>% 
    map(read_html) %>% 
    map(html_node, "#_brand4 span") %>% 
    map(html_text) 

# $`https://www.ratebeer.com/beer/8481/` 
# [1] "Föroya Bjór" 
# 
# $`https://www.ratebeer.com/beer/3228/` 
# [1] "King Brewing Company" 
# 
# $`https://www.ratebeer.com/beer/10325/` 
# [1] "Bavik-De Brabandere" 

(注意,没有必要使用html_nodes(复数)而不是html_node(单数))。

混合dplyr/purrr替代方案,它可以让你保持每个HTML文档的整洁数据帧,如果需要重新使用它们:

res <- 
    table %>% 
    mutate(html = map(link, read_html), 
     brand_node = map(html, html_node, "#_brand4 span"), 
     scrapedname = map_chr(brand_node, html_text)) 

htmlbrand_node列存储外部指针和不非常便于打印的,所以这里没有他们所得到的数据框:

select(res, - html, - brand_node) 

# beer_brewerid         link   scrapedname 
# 1   8481 https://www.ratebeer.com/beer/8481/   Föroya Bjór 
# 2   3228 https://www.ratebeer.com/beer/3228/ King Brewing Company 
# 3   10325 https://www.ratebeer.com/beer/10325/ Bavik-De Brabandere 

glimpse(res) 

# Observations: 3 
# Variables: 5 
# $ beer_brewerid <chr> "8481", "3228", "10325" 
# $ link   <chr> "https://www.ratebeer.com/beer/8481/", "https://www.ratebeer.com/beer/3228/", "https://www.ratebeer.com/beer/10325/" 
# $ scrapedname <chr> "Föroya Bjór", "King Brewing Company", "Bavik-De Brabandere" 
# $ html   <list> [<html lang="en">, <html lang="en">, <html lang="en">] 
# $ brand_node <list> [<span itemprop="name">, <span itemprop="name">, <span itemprop="name">] 

对于超时问题,你可以,也每@Thomas K公司的评论,只是包裹在read_htmlsafely()possibly()(这确实是替代tryCatch):

safe_read_html <- possibly(read_html, otherwise = read_html("<html></html>")) 

但要解决这个你要去太硬的服务器上(可能的)真正的问题,我建议httr::RETRY(),让你,好了,重试,用“指数退避时报”:

safe_retry_read_html <- possibly(~ read_html(RETRY("GET", url = .x)), otherwise = read_html("<html></html>")) 

刮当一个好的做法是去真正温柔的服务器上,所以你甚至可以手动每个请求前添加一个偏移时间,与Sys.sleep(1 + runif(1))例如。

table$link %>% 
    c("https://www.wrong-url.foobar") %>% 
    purrr::set_names() %>% 
    map(~ { 
    Sys.sleep(1 + runif(1)) 
    safe_retry_read_html(.x) 
    }) %>% 
    map(html_node, "#_brand4 span") %>% 
    map_chr(html_text) 

# https://www.ratebeer.com/beer/8481/ https://www.ratebeer.com/beer/3228/ 
#      "Föroya Bjór"    "King Brewing Company" 
# https://www.ratebeer.com/beer/10325/   https://www.wrong-url.foobar 
#    "Bavik-De Brabandere"         NA 

最后,还有你的另外一个问题关于by_row()/rowwise()
首先,请注意by_row已经从purrr开发版本中删除,并移动到一个单独的包,purrrlyr,在那里它反正过时,它的建议“用的组合:tidyr::nest(); dplyr::mutate(); purrr::map()

help("rowwise")rowwise主要是意在“用于do()结果当您创建列表变量”。

所以,不,既不“的真正含义此任务”,他们将是多余的。

+0

感谢这样一个详细的解释,正如我刚才意识到,横行不正是我想要做的笑。我看到了一些可能使用的解决方案,但看起来有点粗略。我有大约7000个URL需要通过,所以这非常有用。 – petergensler

+0

您是否应该使用magrittr管道将多个地图命令链接在一起?我真的很喜欢使用的地图与管道的想法,但我有点不确定什么〜{}与地图命令 – petergensler

+0

做你既可以链'图()单曲像我一样,或者把一切都在一个。这是我猜想的味道问题。对于代字符“〜”的含义,请参阅例如'purrr'小插曲。它基本上是一个缩写的匿名函数,通过多种公式符号 –

相关问题