我想知道我是否可以对以下问题有一些想法:
当使用
rvest
从多个网站抓取多个元素时,很容易发生请求的 html_element 不存在的情况,例如一个站点。因此,投资
返回,至少在下面的示例中,character(0)
。
将这样的
character(0)
元素包含到 tibble 中不会渲染相关内容
列/值 NA,但将整个 tibble 渲染为零行 tibble(如果 tibble 只有一行)。
我希望下面的例子能让这一点更清楚。
library(tidyverse)
library(rvest)
#Here my urls:
vec_urls <- c("https://www.noe.gv.at/noe/Achau.html", "https://www.noe.gv.at/noe/Aderklaa.html")
#Here the scraping function iterating over the urls:
fn_get_address <- function(municip_url) {
municip_name <-{{municip_url}} %>%
rvest::read_html() %>%
rvest::html_elements(., xpath="//h1[@data-cms-title='Name der Gemeinde']/text()") %>%
html_text()
municip_web <- {{municip_url}} %>%
rvest::read_html() %>%
rvest::html_elements(.,xpath="//div[contains(@class, 'col-xs-12') and .//*[contains(text(), 'Kontakt:')]]") %>%
rvest::html_elements("a") %>%
rvest::html_attr("href") %>%
stringr::str_subset(., regex("www"))
tibble("municip_name"=municip_name, "municip_web"=municip_web)
}
fn_get_address(vec_urls[1]) #works
#> # A tibble: 1 × 2
#> municip_name municip_web
#> <chr> <chr>
#> 1 Achau http://www.achau.gv.at
fn_get_address(vec_urls[2]) # doesn't work; returns 0 row tibble
#> # A tibble: 0 × 2
#> # ℹ 2 variables: municip_name <chr>, municip_web <chr>
vec_urls[2]
返回 0 行 tibble 的原因是
municip_web
返回 character(0)
。它在源中不存在。当组合到 tibble 时,整个 tibble 变成零行 tibble。
municip_web_2 <- vec_urls[2] %>%
rvest::read_html() %>%
rvest::html_elements(.,xpath="//div[contains(@class, 'col-xs-12') and .//*[contains(text(), 'Kontakt:')]]") %>%
rvest::html_elements("a") %>%
rvest::html_attr("href") %>%
stringr::str_subset(., regex("www"))
municip_web_2 #character(0)
#> character(0)
municip_name_2 <- vec_urls[2] %>%
rvest::read_html() %>%
rvest::html_elements(., xpath="//h1[@data-cms-title='Name der Gemeinde']/text()") %>%
html_text()
municip_name_2 #ok
#> [1] "Aderklaa"
#combining leads to zero row tibble
tibble("municip_name"=municip_name_2, "municip_web"=municip_web_2)
#> # A tibble: 0 × 2
#> # ℹ 2 variables: municip_name <chr>, municip_web <chr>
所以,这是我的问题:因为我们永远不能排除 html 元素的可能性 返回字符(0) 总是有可能丢失小标题。 你有什么方法来控制这个?除非我弄错了,这也意味着 我们在抓取时永远不应该使用 tibble(.... ),因为我们永远无法排除某些页面上缺少某些 html 元素?
我目前的方法如下,该方法有效,但我想知道 是否还有其他更直接的解决方案。
list("municip_name"=municip_name_2, "municip_web"=municip_web_2) %>%
modify_if(., .p=is_empty, \(x) NA) %>%
enframe() %>% pivot_wider() %>%unnest(cols=everything())
#> # A tibble: 1 × 2
#> municip_name municip_web
#> <chr> <lgl>
#> 1 Aderklaa NA
我很好奇其他人是如何处理这个问题的。 非常感谢!
要处理文档结构不包含每个实体的所有元素的情况,您可以迭代容器元素,将数据收集到命名列表或向量的列表中,并将其传递给
bind_rows()
。可以在这里找到一个这样的例子 - https://stackoverflow.com/a/76619623/646761
但在这种特殊情况下,这并不是真正的问题,因为所有联系方式都在一个结构良好的表格中。尽管我们仍然可以使用非常相似的模式来避免调用
tibble()
,同时将请求数量减少一半:
library(rvest)
library(dplyr)
vec_urls <- c("https://www.noe.gv.at/noe/Achau.html", "https://www.noe.gv.at/noe/Aderklaa.html")
fn_get_contacts <- function(municip_url) {
html <- read_html(municip_url)
municip <-
html_element(html, xpath="//h1[@data-cms-title='Name der Gemeinde']/text()") |>
html_text() |>
setNames("municip")
cont <-
html_element(html, xpath="//div[contains(@class, 'col-xs-12') and .//*[contains(text(), 'Kontakt:')]]/table") |>
html_table() |>
tibble::deframe()
c(municip, cont) # return a named vector
}
fn_get_contacts(vec_urls[2])
#> municip Telefon: Fax:
#> "Aderklaa" "(0 22 47) 22 90" ""
#> E-Mail: Homepage:
#> "[email protected]" ""
lapply(vec_urls, fn_get_contacts) |>
bind_rows()
#> # A tibble: 2 × 5
#> municip `Telefon:` `Fax:` `E-Mail:` `Homepage:`
#> <chr> <chr> <chr> <chr> <chr>
#> 1 Achau (0 22 36) 715 83 "(0 22 36) 715 83 33" [email protected] "www.achau…
#> 2 Aderklaa (0 22 47) 22 90 "" gemeinde@aderklaa… ""
您可以使用测试“identical()”来检查函数的部分是否返回字符(0),然后将其更改为例如不适用
fn_get_address <- function(municip_url) {
municip_name <-{{municip_url}} %>%
rvest::read_html() %>%
rvest::html_elements(., xpath="//h1[@data-cms-title='Name der Gemeinde']/text()") %>%
html_text()
municip_web <- {{municip_url}} %>%
rvest::read_html() %>%
rvest::html_elements(.,xpath="//div[contains(@class, 'col-xs-12') and .//*[contains(text(), 'Kontakt:')]]") %>%
rvest::html_elements("a") %>%
rvest::html_attr("href") %>%
stringr::str_subset(., regex("www"))
if (identical(municip_web, character(0)))
municip_web <- NA
tibble("municip_name"=municip_name, "municip_web"=municip_web)
}