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

使用R抓取层级网页表单所有选项组合及优化需求

尼日利亚INEC投票单元层级表单抓取解决方案

问题核心

你遇到的问题本质是递进式AJAX表单而非传统HTML表单:页面的LGA/Ward/Polling Unit选项通过异步请求动态加载,而非静态表单提交;原代码依赖rvest解析静态HTML,自然拿不到后续层级,且因表单无action属性导致提交报错。同时需要解决列表命名、慢网页抓取效率问题,最终生成标准化表格。

核心解决步骤

1. 定位异步请求接口

用浏览器开发者工具(F12→Network→XHR)抓包:

  • 选择State后,页面会发送GET/POST请求到后台接口,返回对应LGA的JSON/HTML数据
  • 同理,选择LGA后请求Ward接口,选择Ward后请求Polling Unit接口
  • 复制这些接口的URL、请求参数(比如State ID、LGA ID)

2. 层级数据抓取与列表命名

  • 先抓取所有State的名称和ID(可从页面静态下拉框或接口获取)
  • 循环每个State,请求其对应的LGA列表;再循环每个LGA,请求对应的Ward列表
  • 每个Ward对应的Polling Unit结果列表,命名为{State名称}-{LGA名称}-{Ward名称}格式

3. 慢速不稳定网页的高效抓取策略

  • 并行处理:用furrr包开启多线程并行请求,减少总耗时
  • 重试机制:用httr2::req_retry()设置重试次数(比如3次),处理请求失败
  • 结果缓存:用memoise包缓存已请求的State/LGA/Ward数据,避免重复请求
  • 超时设置:给每个请求设置超时(比如10秒),防止长时间阻塞

完整代码示例

library(httr2)
library(purrr)
library(furrr)
library(memoise)
library(dplyr)

# 初始化并行处理,根据CPU核心数调整workers数量
plan(multisession, workers = 4)

# 定义带缓存和重试的请求函数,适配接口返回格式调整resp_body_*
memoised_request <- memoise(function(url, params = list()) {
  req <- request(url) %>%
    req_url_query(!!!params) %>%
    req_retry(max_tries = 3, backoff = ~ 2^.x) %>%
    req_timeout(10) %>%
    req_perform() %>%
    resp_body_json()
})

# 1. 获取所有State列表(替换为实际抓包的接口)
state_url <- "https://inecnigeria.org/api/elections/states"
states <- memoised_request(state_url) %>%
  map_dfr(~tibble(state_name = .x$name, state_id = .x$id))

# 2. 抓取对应State的LGA列表
get_lgas <- function(state_id, state_name) {
  lga_url <- "https://inecnigeria.org/api/elections/lgas"
  memoised_request(lga_url, params = list(state_id = state_id)) %>%
    map_dfr(~tibble(
      state_name = state_name,
      lga_name = .x$name,
      lga_id = .x$id
    ))
}

# 3. 抓取对应LGA的Ward列表
get_wards <- function(lga_id, state_name, lga_name) {
  ward_url <- "https://inecnigeria.org/api/elections/wards"
  memoised_request(ward_url, params = list(lga_id = lga_id)) %>%
    map_dfr(~tibble(
      state_name = state_name,
      lga_name = lga_name,
      ward_name = .x$name,
      ward_id = .x$id
    ))
}

# 4. 抓取对应Ward的Polling Unit数据
get_polling_units <- function(ward_id, state_name, lga_name, ward_name) {
  pu_url <- "https://inecnigeria.org/api/elections/polling-units"
  memoised_request(pu_url, params = list(ward_id = ward_id)) %>%
    map_dfr(~tibble(
      state_name = state_name,
      lga_name = lga_name,
      ward_name = ward_name,
      polling_unit_id = .x$id,
      polling_unit_name = .x$name,
      remark = .x$remark %||% "" # 处理空备注
    ))
}

# 5. 层级抓取并生成命名列表
lgas <- future_map2_dfr(states$state_id, states$state_name, get_lgas)
wards <- future_pmap_dfr(lgas, ~get_wards(..3, ..1, ..2))
pu_list <- future_pmap(wards, function(state_name, lga_name, ward_name, ward_id) {
  pu_data <- get_polling_units(ward_id, state_name, lga_name, ward_name)
  list_name <- paste(state_name, lga_name, ward_name, sep = "-")
  set_names(list(pu_data), list_name)
}) %>% flatten()

# 6. 合并为最终标准化表格
final_table <- bind_rows(pu_list)

# 查看结果
head(final_table)

最终输出说明

生成的final_table包含以下指定列:

  • state_name:州名称
  • lga_name:地方政府区域名称
  • ward_name:选区名称
  • polling_unit_id:投票单元ID
  • polling_unit_name:投票单元名称
  • remark:备注信息

内容的提问来源于stack exchange,提问作者Joke O.

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 06:35:29