2017-04-04 68 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'小插曲。它基本上是一個縮寫的匿名函數,通過多種公式符號 –

相關問題