【问题标题】:Need help looping these functions over a list of URLs and combining the aggregate data in a table需要帮助在 URL 列表上循环这些函数并将聚合数据组合到一个表中
【发布时间】:2021-08-05 20:29:16
【问题描述】:

有一个旧的 HTML 网站,其中包含有关植物病毒的综合研究数据。我有兴趣提取单个病毒物种的易感宿主物种和不易感宿主物种数据。

The parent URL containing all individual, paginated URLs for individual species is here.

网址从 001 到 911 进行分页。An example of one of these URLs, in this case for Abelia latent tymovirus, is found here.

在此板上的某个人的帮助下,我设法生成了代码,以从单个 URL 中仅提取易受感染/不易受感染的数据。代码:

library(rvest)
library(stringr)

#### Preparing for the loop ####

## URL template
url <- 'http://bio-mirror.im.ac.cn/mirrors/pvo/vide/'

## List of all URLs to visit
list_of_pages <- str_c(url, 'descr', c("001", "002", "003", "004", "005", "006", "007", "008", "009", "010","011","012","013","014","015","016","017","018","019","020","021","022","023","024","025","026","027","028","029","030","031","032","033","034","035","036","037","038","039","040","041","042","043","044","045","046","047","048","049","050","051","052","053","054","055","056","057","058","059","060","061","062","063","064","065","066","067","068","069","070","071","072","073","074","075","076","077","078","079","080","081","082","083","084","085","086","087","088","089","090","091","092","093","094","095","096","097","098","099",100:911))
list_of_pages <- str_c(list_of_pages, ".htm")

#### Functions to be executed for each URL

## Obtain URL data for one species (will need to change for loop)
pvo <- read_html("http://bio-mirror.im.ac.cn/mirrors/pvo/vide/descr001.htm")

## Extract URL-specific virus species identifier and cleanup
virus_species <- pvo %>% html_element("center+ h1") %>% html_text()%>% str_replace_all("[\n]" , " ")

## Select only data in node h4, include listitems, and cleanup
all_values <- pvo %>% html_elements("h4, li") %>% html_text() %>% str_replace_all("[\n]" , "")

## Index headings in h4 to isolate susceptibility data
sus_index <- grep('Susceptible host species', all_values, fixed = TRUE)
insus_index <- grep('Insusceptible host species', all_values, fixed = TRUE)
family_sus_index <- grep('Families containing susceptible hosts', all_values, fixed = TRUE)

## Extract susceptible species data
susceptible_species <- all_values[(sus_index+1):(insus_index-1)]

## Extract insusceptible species data
insusceptible_species <- all_values[(insus_index+1):(family_sus_index-1)]

现在我想将这些函数应用于我的 list_of_pages 并将数据聚合到一个数据帧中,理想情况下看起来像这样:

有人可以帮我完成这个吗?我对循环的经验很少,主要使用 dplyr。

编辑:我忘了补充一件非常重要的事情:许多 URL 不包含易感性/易感性数据,因为研究根本没有进行。循环必须能够在这些情况下继续并且不会终止。

这些网址的示例:

包含敏感数据但不包含不敏感数据: http://bio-mirror.im.ac.cn/mirrors/pvo/vide/descr565.htm

包含既不敏感也不敏感的数据: http://bio-mirror.im.ac.cn/mirrors/pvo/vide/descr562.htm

【问题讨论】:

  • 您能否添加一两个不包含易感性/易感性数据的 URL 示例?
  • 当然!我在帖子中的编辑下添加了示例。
  • 我现在也意识到我的索引不适用于这些情况。为什么 HTML 这么难从...

标签: r web-scraping rvest


【解决方案1】:

试试这个:

library(rvest)
library(stringr)

#### Preparing for the loop ####

## URL template
url <- 'http://bio-mirror.im.ac.cn/mirrors/pvo/vide/'

## List of all URLs to visit
list_of_pages <- str_c(url, 'descr', c("001", "002", "003", "004", "005", "006", "007", "008", "009", "010","011","012","013","014","015","016","017","018","019","020","021","022","023","024","025","026","027","028","029","030","031","032","033","034","035","036","037","038","039","040","041","042","043","044","045","046","047","048","049","050","051","052","053","054","055","056","057","058","059","060","061","062","063","064","065","066","067","068","069","070","071","072","073","074","075","076","077","078","079","080","081","082","083","084","085","086","087","088","089","090","091","092","093","094","095","096","097","098","099",100:911))
list_of_pages <- str_c(list_of_pages, ".htm")
#list_of_pages <- list_of_pages[641:n_distinct(list_of_pages)]
#### Functions to be executed for each URL

df <- data.frame()

for (pages in list_of_pages) {
  print(pages)
  ## Obtain URL data for one species (will need to change for loop)
  
  ## First catch the Error
  possible_error <- tryCatch(
    pvo <- read_html(pages),
    error = function(e)
      e
  )

  ## If any Error found then just capture it in virus_species column
  ## You will find  "Failed to parse text" where 
  if (inherits(possible_error, 'error')) {
    temp_df <- data.frame(
      pages,
      virus_species = possible_error$message,
      susceptible_species = NA,
      insusceptible_species = NA
    )
    
    df <- rbind(df, temp_df)
    next
  }
  
  ## If no error found reading the html then collect all necessary data
  if (!inherits(possible_error, 'error')) {
    #pvo <- read_html(pages)
    
    ## Extract URL-specific virus species identifier and cleanup
    virus_species <-
      pvo %>% html_element("center+ h1") %>% html_text() %>% str_replace_all("[\n]" , " ")
    
    ## Select only data in node h4, include listitems, and cleanup
    all_values <-
      pvo %>% html_elements("h4, li") %>% html_text() %>% str_replace_all("[\n]" , "")
    
    ## Index headings in h4 to isolate susceptibility data
    sus_index <-
      grep('Susceptible host species', all_values, fixed = TRUE)
    insus_index <-
      grep('Insusceptible host species', all_values, fixed = TRUE)
    family_sus_index <-
      grep('Families containing susceptible hosts', all_values, fixed = TRUE)
    
    ## Extract susceptible species data
    #susceptible_species <- all_values[(sus_index + 1):(insus_index - 1)]
    
    if (length(sus_index) > 0L & length(insus_index) > 0L) {
      susceptible_species <-
        all_values[(sus_index + 1):(insus_index - 1)]
    } else{
      susceptible_species <- NA
    }
    
    ## Extract insusceptible species data
    if (length(insus_index) > 0L & length(family_sus_index) > 0L) {
      insusceptible_species <-
        all_values[(insus_index + 1):(family_sus_index - 1)]
    } else{
      insusceptible_species <- NA
    }
    
    ll <-
      sapply(list(
        virus_species,
        susceptible_species,
        insusceptible_species
      ),
      length)
    
    mll <- max(ll)
    
    temp_df <- data.frame(
      pages = rep(pages, mll),
      virus_species = rep(virus_species, mll),
      susceptible_species = c(susceptible_species, rep(NA, mll - ll[2])),
      insusceptible_species = c(insusceptible_species, rep(NA, mll - ll[3]))
    )
    
    df <- rbind(df, temp_df)
    ## uncomment below line if you need the delay 
    ##Sys.sleep(1) 
    
  }
}

df

For better error handling in r see here

【讨论】:

  • 我非常感谢这个回复。在我尝试之前,您介意在循环中添加 1000 毫秒的延迟,这样我就不会使网站超载或被服务器锁定吗?
  • 您可以在循环中的df &lt;- rbind(df, temp_df) 之后添加Sys.sleep(time)。这里时间以秒为单位。即在处理一个网址后,它将等待您提供的时间,然后再加载下一个网址。
  • @DieterKahl 我已经用更好的错误处理更新了答案,它适用于所有网址。
  • 这非常好用。非常感谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-11-22
  • 1970-01-01
  • 2011-12-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多