【问题标题】:Is there a way to collect web data selectively in R?有没有办法在 R 中选择性地收集网络数据?
【发布时间】:2020-09-19 22:34:37
【问题描述】:

我正在尝试从德国乐天网站上抓取数据。乐天公司是一家总部位于日本的全球知名企业,通过互联网销售各种商品。问题是他们为不同的国家采用不同的市场策略。例如,在美国,在支付所谓的订阅费之前无法获得产品。在德国则不同,人们可以立即获得产品和价格。因此,乐天的链接似乎带有地理标记,即如果从另一个目的地登录,则无法看到内容。此序言对于尝试按照我的步骤操作并遇到连接错误的每个人都很重要。
好的,也就是说,我想读取数据并将其保存到数据框中。

这是我的初始代码:

library(rvest)
library(purrr)
library(dplyr)     

rakuten <- "https://www.rakuten.de/suchen/kitchenAid?category=0"
ra_html <- read_html(rakuten)

title <- html_nodes(ra_html, ".vw-productCard .name") 
price <- html_nodes(ra_html, ".vw-productCard .price .actual")
discount <- html_nodes(ra_html, ".vw-productCard .thumb .discount .text") 

如您所见,我想抓取产品描述(标题对象)、价格(价格对象)和折扣可用性(折扣对象)(如果有)。他们出售的每种产品总是有描述和价格(我正在查看 KitchenAid 价格),但折扣很少发生

然后我解析数据:

urlrakuten <- sprintf("https://www.rakuten.de/suchen/kitchenAid?category=0", 1:10)

#define empty data frame to store all data
alllistings <- data.frame()

for (i in urlrakuten){
  
  print(i)
  #read the page just once
  page <- read_html(i)
      
  # parse titles
 title <- page%>%html_nodes('.vw-productCard .name') %>% html_text()
 
  # parse prices
  price <- page %>% html_nodes('.vw-productCard .price .actual') %>% html_text()
  
  # parse discounts
  discount <- page %>% html_nodes('.vw-productCard .thumb .discount .text') %>%  html_text()

  #create temporary dataframe to store data from this loop
  tempdf <- data.frame(title, price, discount) 
  
  #combine temp with all data
  alllistings <- rbind(alllistings, tempdf)
}

它对前两个对象的效果非常好,但对最后一个对象不适用(折扣)。第一页只有四个折扣,R 将所有折扣都刮掉,然后用这四个值的重复填充其余行,请参阅我的输出:

我肯定遗漏了一些东西,但我不知道如何修复它。我希望有相同的输出,第三列值组织到它们所属的行,其余的只填充 NA。

【问题讨论】:

  • 这个答案有帮助吗:stackoverflow.com/questions/63540089/…
  • @ Dave2e 感谢您的快速回复,Dave。不,不幸的是,这种重新排列只给了我三行(观察)的 NA。我在您的代码中包含了带有 url 的第四列,这些 url 被很好地收集和呈现。我认为我在这里的包装实现是不正确的。

标签: r web-scraping na rvest


【解决方案1】:

遵循本题的策略:How to get rid of the error while scraping web in R?。由于不是每个产品都有折扣,使用 html_nodes() 函数会导致您看到的问题,因为它只返回找到的节点。
因此解决方案是为产品的所有父节点生成一个向量,然后用html_node() 解析每个父节点。 html_node() 函数将始终返回一个值,即使它只是 NA。

另请注意:我使用lapply 函数返回数据帧列表(每页一个)并将它们同时绑定在一起。与循环内绑定的增量方法相比,这是一个显着的性能改进。

library(rvest)
library(dplyr)
library(tibble)

readpage <- function(url){
   #read the page once
   page <-read_html(url)
   
   #parse out the parent nodes (the product)
   products <- page %>% html_nodes( "li.vw-productCard")
   
   #Now extract one piece of imformation per parent
   #title
   title <- products%>%html_node('.name') %>% html_text() 
   
   # parse prices
   price <- products %>% html_node('.price .actual') %>% html_text() %>% trimws()
  
   # parse discounts (html_node will return NA if no discount is available)
   discount <- products %>% html_node('.thumb .discount .text') %>%  html_text()
   
   #return a tibble/data,frame
   tibble(title, price, discount, url)
}

listofurls <- paste0("https://www.rakuten.de/suchen/kitchenAid?category=0&page=", 1:10)

dfs <- lapply(listofurls, function(url){ readpage(url)})
finalanswer <- bind_rows(dfs)

【讨论】:

  • @Dave2e 感谢您的详细解释和工作程序,Dave。像魅力一样工作,出色。我最深切的赞赏和尊重。我认为我的节点定义也不正确。您能否建议我一个程序/方法来为正确的实体确定正确的节点。
  • @kshtwork,有些人使用名为“selector-gadget”的工具,但我更喜欢使用浏览器中的开发人员工具来检查结构。如果它是一个动态的 Java 脚本页面,这也会有所帮助。大多数人都犯了一个错误,即直接跳到首先收集所有细节。最好从更高的层次开始,即个别细节共有的父节点。在这种情况下,从产品节点开始,然后从每个产品中提取详细信息。这是细微的差别,但对成功很重要。希望这会有所帮助。
  • @ Dave2e 是的,这让我对人们使用的方法有了更广泛的了解。再次,非常感谢。
猜你喜欢
  • 2010-09-05
  • 2020-07-31
  • 2023-03-03
  • 1970-01-01
  • 2011-01-19
  • 2021-10-04
  • 2019-11-25
相关资源
最近更新 更多