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

如何用R的selenider/rvest点击JS按钮抓取多页选举数据表格?

解决方案:无需Selenium,通过表单回发爬取多页表格

这类ASP.NET驱动的分页页面,核心是通过表单POST回发实现翻页,而非直接的GET链接。我们可以用rvest+httr模拟这个过程,步骤如下:

1. 分析分页机制

页面的分页按钮触发的是__doPostBack JavaScript函数,本质是向服务器提交包含状态参数的表单,关键参数包括:

  • __VIEWSTATE、__VIEWSTATEGENERATOR、__EVENTVALIDATION:ASP.NET的页面状态验证字段,每次回发后会更新
  • __EVENTTARGET:触发回发的控件ID(这里是表格的ID:ctl00$ContentPlaceHolderBody$gvLocalities)
  • __EVENTARGUMENT:分页指令,格式为Page$页码(如Page$2表示第2页)

2. 完整爬虫代码

加载依赖包

library(rvest)
library(httr)
library(tidyverse)

初始化会话与获取第一页数据

# 目标页面URL
base_url <- "https://electorate.aec.gov.au/LocalitySearchResults.aspx?filter=0872&filterby=Postcode"

# 创建会话以保持Cookie和会话状态
session <- session(base_url)
first_page <- session %>% read_html()

# 提取第一页表格
first_table <- first_page %>% 
  html_element("#ctl00_ContentPlaceHolderBody_gvLocalities") %>% 
  html_table(header = TRUE) %>% 
  clean_names()

# 提取页面状态字段(必须,否则后续回发会失败)
viewstate <- first_page %>% html_element("#__VIEWSTATE") %>% html_attr("value")
viewstategenerator <- first_page %>% html_element("#__VIEWSTATEGENERATOR") %>% html_attr("value")
eventvalidation <- first_page %>% html_element("#__EVENTVALIDATION") %>% html_attr("value")

# 提取总页数(从分页摘要文本中解析)
page_summary <- first_page %>% html_element(".pagingSummary") %>% html_text()
total_pages <- as.integer(str_extract(page_summary, "of (\\d+)") %>% str_remove("of "))

定义单页爬取函数

get_single_page <- function(page_num, session, vs, vsg, ev) {
  # 构造POST表单数据
  form_data <- list(
    "__VIEWSTATE" = vs,
    "__VIEWSTATEGENERATOR" = vsg,
    "__EVENTVALIDATION" = ev,
    "__EVENTTARGET" = "ctl00$ContentPlaceHolderBody$gvLocalities",
    "__EVENTARGUMENT" = paste0("Page$", page_num)
  )
  
  # 提交POST请求
  response <- session %>% session_post(
    url = base_url,
    body = form_data,
    encode = "form"
  )
  
  # 解析返回页面
  new_page <- response %>% read_html()
  
  # 提取当前页表格
  current_table <- new_page %>% 
    html_element("#ctl00_ContentPlaceHolderBody_gvLocalities") %>% 
    html_table(header = TRUE) %>% 
    clean_names()
  
  # 更新状态字段(下一页请求需要用新的状态值)
  new_vs <- new_page %>% html_element("#__VIEWSTATE") %>% html_attr("value")
  new_vsg <- new_page %>% html_element("#__VIEWSTATEGENERATOR") %>% html_attr("value")
  new_ev <- new_page %>% html_element("#__EVENTVALIDATION") %>% html_attr("value")
  
  # 返回表格和新状态
  list(table = current_table, vs = new_vs, vsg = new_vsg, ev = new_ev)
}

遍历所有页面并合并数据

# 初始化存储列表
all_tables <- list(first_table)
current_vs <- viewstate
current_vsg <- viewstategenerator
current_ev <- eventvalidation

# 从第2页开始循环爬取
for (page in 2:total_pages) {
  page_result <- get_single_page(page, session, current_vs, current_vsg, current_ev)
  all_tables[[page]] <- page_result$table
  
  # 更新状态字段
  current_vs <- page_result$vs
  current_vsg <- page_result$vsg
  current_ev <- page_result$ev
  
  # 可选:添加延迟避免请求过快被拦截
  Sys.sleep(1)
}

# 合并所有表格为数据框
final_data <- bind_rows(all_tables)

关键说明

  • 必须使用session保持会话状态,否则服务器会拒绝重复请求
  • 每次回发后要更新__VIEWSTATE等状态字段,这些值是动态生成的,不能复用
  • 提取总页数时,依赖页面的.pagingSummary元素文本(格式为Page X of Y),如果页面结构变化,需要调整正则提取规则

内容的提问来源于stack exchange,提问作者Hassan Nasir Mirbahar

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.01 13:32:29