使用 R 抓取带有更多嵌套页面的多个网页

时间:2021-01-25 11:18:16

标签: r web-scraping nested rvest

我是 R 新用户。我正在尝试为我的问题找到解决方案,但找不到确切的解决方案,这肯定是我的错。 无论如何:我有这个网站,我想抓取并放在 .xlsx 工作表上:“http://www.tbca.net.br/base-dados/composicao_estatistica.php?pagina=1&atuald=1”。 基本上,我对表第一行所示的六个变量感兴趣:codigo、nome、nome inglés、ecc。对于数据集的所有 53 页。 这些变量中的任何一个都包含指向其他嵌套页面的链接,这些页面的变量(componente、unidade、ecc)我也应该抓取以便我拥有这样的表:

codigo   nome  nome_inglés  nome_cientifico  grupo  marca  componente   unidade
C105      bla    blabla          blabla195    aq      awa    Energia      11    
C105      bla    blabla          blabla195    aq      awa    carboidrato  45
C105      bla    blabla          blabla195    aq      awa    proteina     22
C106      blu    blublu          blublu196    ar      owo    Energia      22    
C106      blu    blublu          blublu196    ar      owo    carboidrato  33
C106      blu    blublu          blublu196    ar      owo    proteina     44

然而,我做了各种尝试,但都没有成功。

这是我的代码:

library(rvest)
library(dplyr)
library(data.table)
library(tidyverse)
library(stringr)

 get_tbca = function(tbca_link) {
 tbca_page = read_html(tbca_link)
 tbca_data = tbca_page %>% html_nodes("tr :nth-child(1)") %>%
html_text() 
 return(tbca_data)
  }


 tbca_df <- data.frame()

 lupin_fun <- function(page_result){

 print(paste("Page:", page_result))  

 link = paste0("http://www.tbca.net.br/base-dados/composicao_estatistica.php?pagina=", 
            page_result, "&atuald=1")
 page = read_html(link)

 codigo = page %>% html_nodes("td:nth-child(1) a") %>%  html_text()
 codigo_links <- page %>%  html_nodes("td:nth-child(1)") %>%
html_attr("href") %>% paste("http://www.tbca.net.br/base-dados/int_composicao_estatistica.php?cod_produto=", ., sep = "")
 nome = page %>%  html_nodes("td:nth-child(2) a") %>%  html_text()
 nome_ingles = page %>%   html_nodes("td:nth-child(3) a") %>%  html_text()
 nome_cientifico = page %>%  html_nodes("td:nth-child(4) a") %>%  html_text()
 grupo = page %>%  html_nodes("td:nth-child(5) a") %>%  html_text()
 marca = page %>%  html_nodes("td:nth-child(6) a") %>%  html_text()
 tbca_reference = sapply(codigo_links, FUN = get_tbca, USE.NAMES = FALSE)

 tbca_df <- cbind(tbca_reference, codigo, nome, nome_ingles, nome_cientifico, grupo, marca, stringsAsFactors = FALSE)

 return(tbca_df)  
 }


 lupin_list <- lapply(1:3, lupin_fun)

 lupin_result <- do.call(rbind, lupin_list)

1 个答案:

答案 0 :(得分:1)

我认为您走对了路。我可以看到的两个问题:

  1. 我认为在这种情况下使用 html_table 容易得多。您可以直接将表格作为数据框获取,而不是获取单元格/列然后将所有内容绑定在一起。
  2. 如果我发现的问题出在 codigo_links 中,则为一个。在提取 <a> 属性之前,您需要在每个 <td> 中获取带有 href 标签的节点。我在我的解决方案中修复了这部分。

我是这样做的:

library(rvest)
library(dplyr)

get.table.in.link <- function(url1) {
  # get code of food from link
  cod_produto <- strsplit(url1, 'cod_produto=')[[1]][2]

  # get table in nested link 
  table.2 <- read_html(url1) %>% html_table() %>% .[[1]]

  table.3 <- table.2 %>% 
    # filter only Energia, carboidrato, proteina (if you want all rows you can ignore this)
    dplyr::filter(Componente %in% c('Energia', 'Carboidrato total', 'Proteína')) %>%
    # Also choosing subset of columns (you can also change this)
    dplyr::select(Componente, Unidades, `Valor por 100 g`) %>%
    # add column with product code
    dplyr::mutate(Código=cod_produto) %>%
    # change decimal separator and convert to numeric
    dplyr::mutate(`Valor por 100 g`= as.numeric(gsub(',','.',gsub('\\.', '', `Valor por 100 g`))))
  
  return(table.3)
}

get.main.table <- function(page.number) {
  print(paste("Page:", page.number))
  
  url.main <- paste0("http://www.tbca.net.br/base-dados/composicao_estatistica.php?pagina=", page.number, "&atuald=1")
 
  page <- read_html(url.main)
  
  # this is simpler to get the main table
  df.table <- page %>% html_table() %>% .[[1]]
  
  # now get list of links in each row (get from first column)
  list.links <- page %>%  html_nodes("td:nth-child(1)") %>% html_nodes('a') %>%
    html_attr("href") %>% paste("http://www.tbca.net.br/base-dados/", ., sep = "")
  
  # get table with details of each product
  # ldply applies function for each element of list.links, then combine results into a data frame
  table.composicao <- plyr::ldply(list.links, get.table.in.link)
  
  # now merge df.table and table.composicao using "Código"   
  df.final <- df.table %>% left_join(table.composicao, by="Código")  
  
  return(df.final)
}

# run get.main.table with arguments = 1, 2, 3 and combine results in a dataframe
df.total <- plyr::ldply(1:3, get.main.table)

结果(即使只加载了 3 页)是一个大表格,所以我不确定它是否正确(因为我无法查看所有内容)。不过好像没问题。

相关问题