首页 > 解决方案 > 从同级多个同名节点抓取网页

问题描述

我想从四个节点中提取以下数据,所有节点都在同一级别并共享相同的代号。

# I was able to extract the first of the four nodes - Property Amenities, using google chrome selector gadget as to identify the nodes.  

library(rvest)
page0_url<-read_html ("https://www.tripadvisor.com/Hotel_Review-g1063979-d1447619-Reviews- 
Solana_del_Ter-Ripoll_Province_of_Girona_Catalonia.html")
result_amenities <- html_text (html_node(page0_url,"._1nAmDotd") %>% html_nodes("div") )

但是,我无法弄清楚如何传递代码以提取名为“房间功能”的第二个对象中的元素。这是在同一节点级别,并且与上面的具有相同的名称代码=。这也是最后一个之后的两个对象的情况,名称为“房间类型”和“很高兴知道”。

标签: rweb-scrapingrvest

解决方案


几乎所有需要的数据(包括您请求的所有数据)都可以通过页面清单在脚本标记中获得,因为它是从那里加载的。您可以使用正则表达式正则表达式输出大量数据。然后编写用户定义的函数来提取所需的信息。

我最初将正则表达式匹配组解析为 json 对象all_data。然后,我查看该列表列表以查找仅与感兴趣的数据相关联的字符串。例如,starRating与您感兴趣的位置数据相关联。get_target_list返回该列表,然后我从中提取我想要的内容。您可以看到location_info包含与酒店设施(包括房间设施)、星级(酒店等级)和语言等相关的数据。

在此处输入图像描述

例如location_info$hotelAmenities$languagesSpokenlocation_info$hotelAmenities$highlightedAmenities$roomFeatures........

NB 正如目前所写的那样search_string,在最初保存在 json 对象中的列表列表中,它对于所需列表是唯一的。我不确定命名列表的名称是否会保持不变,因此选择动态检索正确的列表。


回复:

library(rvest)
library(jsonlite)
library(stringr)
library(magrittr)

is_target_list <- function(x, search_string) {
  return(str_detect(x %>% toString(), search_string))
}

get_target_list <- function(data_list, search_string) {
  mask <- lapply(data_list, is_target_list, search_string) %>% unlist()
  return(subset(data_list, mask))
}
    
r <- read_html("https://www.tripadvisor.com/Hotel_Review-g1063979-d1447619-Reviews-Solana_del_Ter-Ripoll_Province_of_Girona_Catalonia.html") %>%
  toString()

all_data <- gsub("pageManifest:", '"pageManifest":', stringr::str_match(r, "(\\{pageManifest:.*);\\(")[, 2]) %>%
  jsonlite::parse_json()

data_list <- all_data$pageManifest$urqlCache
# target_info <- get_target_list(data_list, 'hotelAmenities')

location_info <- get_target_list(data_list, "starRating") %>%
  unname() %>%
  .[[1]] %>%
  {
    .$data$locations[[1]]$detail
  }

正则表达式:

在此处输入图像描述


推荐阅读