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

R语言网页抓取:提取class='result-item'中特定关键词后内容的gsub正则表达式问题求助

问题:抓取美国115届国会议员数据时,正则表达式提取详情字段失败的排查与修正

我最近尝试抓取美国国会网站上115届议员的数据,想要构建一个包含Name、State、District、Party、ServedHouse、ServedSenate字段的数据框。Name字段通过专属的result-heading class已经顺利提取,但State、District这类详情字段因为都使用相同的result-item class,提取时遇到了麻烦。我参考相关内容修改了代码,试图通过gsub()配合正则表达式提取关键词后的内容,但始终没能成功,推测是正则表达式的写法出了问题。

以下是我最初的代码:

library (dplyr)
library (xml2)
library (rvest)

Congress100 <- read_html("https://www.congress.gov/members?q=%7B%22congress%22%3A115%7D")
name <- Congress100 %>% rvest::html_nodes('body') %>% xml2::xml_find_all("//span[contains(@class, 'result-heading')]") %>% rvest::html_text()
Name <- unique(name)
details <- Congress100 %>% rvest::html_nodes('body') %>% xml2::xml_find_all("//span[contains(@class, 'result-item')]") %>% rvest::html_text()

State <- gsub('^.*State:\ns*|\\s*<\/p>\n.*$', '', details)
District <- gsub('^.*District:\ns*|\\s*<\/p>\n.*$', '', details)
Party <- gsub('^.*Party:\ns*|\\s*<\/p>\n.*$', '', details)
ServedHouse <- gsub('^.*House:\ns*|\\s*<\/p>\n.*$', '', details)
ServedSenate <- gsub('^.*Senate:\ns*|\\s*<\/p>\n.*$', '', details)

df <- data.frame(Name, State, District, Party, ServedHouse, ServedSenate)

问题排查

我仔细检查了代码后,发现两个核心问题:

  1. 数据结构混乱:原代码把所有议员的result-item详情提取成了一个大向量,导致每个gsub处理的是所有详情的混合文本,无法对应到单个议员的信息。
  2. 正则表达式错误:
    • 正则里包含了<\/p>,但html_text()已经把HTML标签完全移除了,这部分内容根本不存在,自然匹配不到。
    • \ns*的写法有误,在R字符串中反斜杠需要转义,应该写成\\s*;而且这种前后截断的匹配逻辑不适合独立的result-item条目。

修正方案

更可靠的做法是先按议员分组,把每个议员的所有详情放在一起处理,再将详情转换成键值对提取对应字段:

library(dplyr)
library(xml2)
library(rvest)
library(purrr)
library(stringr)
library(tibble)

# 读取网页
Congress115 <- read_html("https://www.congress.gov/members?q=%7B%22congress%22%3A115%7D")

# 提取每个议员的容器节点
members <- Congress115 %>% html_nodes(".expanded")

# 定义函数,从单个议员节点提取所有字段
extract_member_info <- function(node) {
  # 提取姓名
  member_name <- node %>% 
    html_node(".result-heading") %>% 
    html_text(trim = TRUE)
  
  # 提取该议员的所有详情项
  member_details <- node %>% 
    html_nodes(".result-item") %>% 
    html_text(trim = TRUE)
  
  # 将详情项转换为命名向量(键值对)
  details_keyval <- member_details %>%
    str_split_fixed(":\\s*", 2) %>%
    as.data.frame(stringsAsFactors = FALSE) %>%
    deframe()
  
  # 提取所需字段,缺失则设为NA
  state <- ifelse(is.null(details_keyval["State"]), NA, details_keyval["State"])
  district <- ifelse(is.null(details_keyval["District"]), NA, details_keyval["District"])
  party <- ifelse(is.null(details_keyval["Party"]), NA, details_keyval["Party"])
  served_house <- ifelse(is.null(details_keyval["House"]), NA, details_keyval["House"])
  served_senate <- ifelse(is.null(details_keyval["Senate"]), NA, details_keyval["Senate"])
  
  # 返回该议员的 tibble
  tibble(
    Name = member_name,
    State = state,
    District = district,
    Party = party,
    ServedHouse = served_house,
    ServedSenate = served_senate
  )
}

# 批量处理所有议员,合并为数据框
congress_df <- map_dfr(members, extract_member_info)

方案说明

  • 先通过.expanded类提取每个议员的独立容器,确保每个议员的信息是独立的,避免混合。
  • 将每个议员的详情项拆分成键值对,这样可以直接通过键名(比如"State")提取对应的值,比正则匹配更稳定。
  • 处理了字段缺失的情况(比如参议员没有District字段),避免出现错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.28 11:02:31