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

如何用rvest抓取FiveThirtyEight中JavaScript渲染的选举预测数据?

解决用rvest抓取FiveThirtyEight 2016民主党初选每日预测数据的问题

嘿,我完全懂你现在的困扰——想用rvest爬取动态生成的图表数据,结果发现数据藏在JavaScript里,静态HTML里只有空壳,折腾了好几天还是没头绪对吧?别慌,咱们一步步拆解这个问题,找到最靠谱的解决方案。

首先得搞明白为什么你之前的代码没效果:read_html()只能抓取页面的静态HTML内容,而这个页面的图表数据是通过JavaScript动态加载并渲染的,所以你拿到的<div id="polling-avg-chart"></div>只是个空容器,实际数据根本不在里面。

接下来给你两个实用的解决思路,优先试试第一个,效率最高:

思路1:直接提取页面中的JavaScript数据变量

很多数据可视化类的网站会把原始数据存在全局JavaScript变量里,方便前端渲染。你可以这样操作:

  1. 找到存储数据的JS变量:打开目标页面,按Ctrl+U查看页面源代码,搜索关键词比如pollingAverage、chartData或者dailyPredictions——你要找的每日预测数据大概率藏在某个类似var xxx = {...}的JS对象里。
  2. 用rvest提取并解析这个变量:把包含数据的脚本内容抓出来,用正则表达式提取JSON格式的字符串,再转成R的数据框。

给你一段可参考的代码:

library(rvest)
library(jsonlite)
library(stringr)

# 目标URL
url <- "https://projects.fivethirtyeight.com/election-2016/national-primary-polls/democratic/"

# 获取页面HTML
page <- read_html(url)

# 抓取所有script标签,筛选出包含目标数据的那个
all_scripts <- html_nodes(page, "script")
target_script <- html_text(all_scripts[str_detect(html_text(all_scripts), "pollingAverage")])

# 用正则提取JS对象的JSON部分(根据实际找到的变量名调整)
json_content <- str_extract(target_script, "var chartData = (.*?);")
json_content <- str_remove_all(json_content, c("var chartData = ", ";"))

# 解析JSON为数据框
polling_df <- fromJSON(json_content)

# 提取每日预测数据(这里的键名需要根据实际JSON结构调整)
daily_predictions <- polling_df$pollingAverage
head(daily_predictions)

这段代码的核心是找到存储数据的JS变量,直接拿到原始的数值数据,比你去转换SVG坐标(cx/cy)靠谱多了——毕竟坐标还要对应坐标轴刻度计算,既麻烦又容易出错。

思路2:用RSelenium模拟浏览器加载动态内容

如果实在找不到JS变量,或者页面的JS逻辑太复杂,那就用RSelenium模拟真实浏览器的行为,等JavaScript执行完、图表渲染完成后再抓取数据。

步骤如下:

library(RSelenium)
library(rvest)
library(jsonlite)

# 启动Chrome浏览器(需要先安装Selenium Server,或者用Docker简化环境配置)
driver <- rsDriver(browser = "chrome", port = 4567L)
remDr <- driver[["client"]]

# 访问目标页面
remDr$navigate("https://projects.fivethirtyeight.com/election-2016/national-primary-polls/democratic/")

# 等待页面完全加载(根据网络情况调整等待时间)
Sys.sleep(5)

# 获取渲染后的页面源代码
page_source <- remDr$getPageSource()[[1]]
page <- read_html(page_source)

# 接下来你可以重复思路1的步骤,提取JS变量;或者直接抓取页面上的元素内容
# 比如抓图表的 tooltip 数据,但还是优先找JS变量更高效

# 用完记得关闭浏览器
remDr$close()
driver$server$stop()

总结一下

优先尝试思路1,直接提取JS里的原始数据,这是最快捷的方式;如果页面结构特殊找不到变量,再用思路2模拟浏览器。这样你就能轻松把每日预测百分比整理成规整的dataframe了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 04:16:05