如何控制字符(0)?

问题描述 投票:0回答:2

我想知道我是否可以对以下问题有一些想法:

当使用

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

我很好奇其他人是如何处理这个问题的。 非常感谢!

r rvest tibble
2个回答
1
投票

要处理文档结构不包含每个实体的所有元素的情况,您可以迭代容器元素,将数据收集到命名列表或向量的列表中,并将其传递给

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… ""

0
投票

您可以使用测试“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)
  
}
© www.soinside.com 2019 - 2024. All rights reserved.