You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用R语言rvest爬取数据时缺失信息处理难题求助

解决rvest爬取时缺失元素导致数据框绑定失败的问题

问题场景

使用rvest爬取https://expresso.pt/api/molecule/search?q=trotinete&page=**PAGENUMBER**&offset=0的文章数据时,当html_nodes或html_text定位的元素不存在,脚本在rbind数据框时崩溃。尝试过tryCatch、if语句但未彻底解决。

核心问题分析

原代码的主要问题是:

  • 直接全局提取节点(如html_nodes(".title a")),若某类节点部分缺失,会导致对应向量长度与其他列不匹配,rbind时因维度不一致报错。
  • 用ifelse(length(.) == 0, NA, .)仅处理了整列全空的情况,无法处理单条数据缺失元素的场景。

优雅处理缺失元素的策略

  1. 按条目容器批量处理:先定位每个文章的父容器节点,再对每个容器单独提取字段,确保每条数据的各字段一一对应,不会出现长度不匹配。
  2. 使用html_element替代html_nodes:针对单元素提取(每个条目仅一个的字段,如标题、日期),html_element会返回与输入节点数量一致的结果,缺失元素自动填充NA,避免空向量。
  3. 避免循环rbind:用列表收集每条数据,最后一次性合并为数据框,既高效又避免维度错误。
  4. 强化单字段错误处理:对可能出错的字段(如文章正文),在提取时加入兜底逻辑。

修改后的完整代码

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

# 定义文章正文提取函数,优化错误处理
get_article <- function(link_article) {
  tryCatch({
    article_page <- read_html(link_article)
    # 提取正文并拼接,若节点不存在则返回NA
    article_text <- article_page %>% 
      html_element("#article-body-1") %>% 
      html_text2()  # html_text2更适合处理带结构的文本
    Sys.sleep(2)
    return(article_text)
  }, error = function(e) {
    message("抓取文章失败: ", link_article)
    return(NA_character_)
  })
}

search_term <- "trotinete"
# 用列表存储所有爬取结果,避免循环rbind
scrape_results <- list()

for(page_result in seq(from = 1, to = 2)) {
  link <- paste0("https://expresso.pt/api/molecule/search?q=", search_term, "&page=", page_result, "&offset=0")     
  message("正在抓取页面: ", link)
  Sys.sleep(2)
  page <- read_html(link)
  
  # 定位每个文章的父容器节点,这是关键:按条目处理
  article_containers <- page %>% html_nodes(".search-result-item")
  
  # 若当前页面无文章,跳过
  if(length(article_containers) == 0) next
  
  # 对每个容器提取字段,确保字段一一对应
  page_data <- map_dfr(article_containers, function(container) {
    tibble(
      title = container %>% html_element(".title a") %>% html_text2(),
      link_article = container %>% html_element(".title a") %>% html_attr("href") %>% 
        {ifelse(grepl("^https://", .), ., paste0("https://expresso.pt", .))},
      date = container %>% html_element(".timeStamp") %>% html_attr("datetime"),
      section = container %>% html_element(".mainSection") %>% html_text2(),
      summary = container %>% html_element(".lead") %>% html_text2(),
      author = container %>% html_element(".author") %>% html_text2()
    )
  })
  
  # 批量提取文章正文
  page_data$complete_article <- map_chr(page_data$link_article, get_article)
  
  # 将当前页面数据加入结果列表
  scrape_results[[page_result]] <- page_data
}

# 合并所有页面数据为数据框
expresso_scraper <- bind_rows(scrape_results)

# 导出为CSV
write.csv2(expresso_scraper, "expresso.csv", row.names = FALSE)

关键修改说明

  • 按条目容器处理:通过html_nodes(".search-result-item")获取每个文章的父容器,确保每条数据的字段提取基于同一容器,不会出现长度不匹配。
  • html_element的使用:替代html_nodes提取单元素,自动为缺失元素填充NA,无需额外判断长度。
  • map_dfr:批量处理容器节点,直接生成数据框,简化代码且避免维度错误。
  • html_text2:比html_text更适合处理网页文本,自动处理换行和多余空格。
  • 列表收集结果:避免循环rbind的性能问题和维度错误,最后用bind_rows合并更高效。

内容的提问来源于stack exchange,提问作者Bruno

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 03:37:24