R语言提取iframe网页图表数据方法

作者:技术拾光

时间:2026-05-27

浏览:556

本文介绍如何使用 chromote 驱动无头 chrome,自动定位并提取由 javascript 动态渲染的 iframe 中的图表原始数据(如 google charts),绕过静态 html 无法获取动态内容的限制,并最终结构化为 r 数据框。 直接从网页上抓取数据是常见需求。然而,当面对由可

文章目录

R语言提取iframe网页图表数据方法

本文介绍如何使用 chromote 驱动无头 chrome,自动定位并提取由 javascript 动态渲染的 iframe 中的图表原始数据(如 google charts),绕过静态 html 无法获取动态内容的限制,并最终结构化为 r 数据框。

直接从网页上抓取数据是常见需求。然而,当面对由可视化建站平台(例如 Wix、Thunderbolt)生成的页面时,操作会变得复杂。这些页面中的交互式图表通常被封装在 `

这意味着,如果直接使用 `httr::GET()` 配合 `rvest` 解析页面源代码,将无法成功——你看到的可能只是一个空的占位 `

`,真正的图表和数据链接都隐藏在 JavaScript 执行后才会出现的 DOM 结构中。

那么,如何可靠地获取这些隐藏数据呢?核心思路是:让 R 控制一个真实的浏览器环境,完整执行页面上的所有 JavaScript,待页面完全渲染后,再从最终的 DOM 结构中精准定位并读取所需数据。下面,我们以 Immostat 市场数据页中的 “Office Investment Prices (gross psqm)” 图表为例,演示完整的实现流程。

步骤一:启动无头浏览器并加载页面

首先,需要一个能执行 JavaScript 的浏览器环境。这里使用 `chromote` 包创建一个无头 Chrome 会话,导航到目标页面,并等待页面加载和 JavaScript 渲染完成。在 `loadEventFired()` 事件触发后,额外等待一小段时间,以确保动态 iframe 也已加载完毕。

library(chromote)
library(rvest)
library(jsonlite)
library(dplyr)

b <- ChromoteSession$new()
b$Page$navigate("https://www.php.cn/link/0c031fe92fdc7596e4f20c56c661319d")
b$Page$loadEventFired()
Sys.sleep(0.5)  # 确保 iframe DOM 已挂载

步骤二:通过语义化 XPath 定位动态 iframe

接下来是关键步骤:找到包含目标图表的 iframe。与其依赖易变的 ID 或 class 属性,不如利用页面上稳定的、用户可见的文本作为锚点。这里,我们以图表标题 “Office Investment Prices (gross psqm)” 所在的 `

` 标签为起点,使用 XPath 向下查找其关联的 iframe 元素,并提取其 `src` 属性。
iframe_src <- b$Runtime$evaluate('
  const xpath = \'//h2[text()="Office Investment Prices (gross  psqm)"]/../following-sibling::div//iframe\';
  const iframe = document.evaluate(xpath, document, null,
    XPathResult.UNORDERED_NODE_ITERATOR_TYPE, null).iterateNext();
  iframe ? iframe.getAttribute("src") : null;
')$result$value

if (is.null(iframe_src)) stop("未找到目标 iframe")
iframe_src
#> "https://www-immostat-com.filesusr.com/html/ae915e_6e3e7e9d19bc8d5af1f3e4b96ae5c686.html"

注意:示例中的 XPath 使用了 `following-sibling::div//iframe`,这是因为在实际 DOM 结构中,目标 iframe 嵌套在标题元素的兄弟 `div` 内。如果页面结构发生变化,需要使用浏览器的开发者工具重新验证并调整此路径。

步骤三:解析 iframe 页面中的图表初始化脚本

获取 iframe 的真实地址后,即可访问其内部页面。通常,像 Google Charts 这类库生成的图表,其原始数据会以 JavaScript 数组的形式写在页面的某个 `

具体方法是:使用 `rvest` 读取 iframe 页面源码,定位包含 `var dataIDF = google.visualization.arrayToDataTable([...])` 这类初始化代码的脚本块。然后,对脚本内容进行修改——将 `arrayToDataTable(...)` 的调用替换为 `JSON.stringify(...)`,这样就能在浏览器的 JavaScript 环境中执行,并得到一个 JSON 字符串。

script_content <- read_html(iframe_src) %>%
  html_element(xpath = "//script[contains(., 'var dataIDF')]") %>%
  html_text()

# 提取并重写:将 arrayToDataTable(...) 替换为 JSON.stringify(...)
data_js <- script_content %>%
  str_split("") %>% unlist() %>%
  str_subset("var dataIDF") %>%
  str_replace("var dataIDF = google\\.visualization\\.arrayToDataTable\\(", "JSON.stringify(")

# 在已运行的 Chrome JS 环境中执行,直接获得 JSON 字符串
json_str <- b$Runtime$evaluate(data_js)$result$value
chart_data_list <- parse_json(json_str)

步骤四:结构化为规范数据框

上一步得到的 `chart_data_list` 是一个嵌套的 R 列表,其结构通常是:第一个子列表为列名,后续的每个子列表代表一行数据。我们需要将其转换为一个规整的数据框。

# 第一行作为列名,其余行转为命名列表
header <- chart_data_list[[1]]
data_rows <- chart_data_list[-1]

# 统一转换:数值列自动识别(避免字符串化)
df <- data_rows %>%
  lapply(setNames, header) %>%
  do.call(rbind, args = _) %>%
  as.data.frame(stringsAsFactors = FALSE) %>%
  # 强制数值列转 numeric(示例中第二列为价格)
  mutate(`Greater Paris Region` = as.numeric(`Greater Paris Region`))

head(df)
#>   Quarter Greater Paris Region
#> 1 Q1 2006                 4490
#> 2 Q2 2006                 4631
#> 3 Q3 2006                 4803
#> 4 Q4 2006                 4837
#> 5 Q1 2007                 4953
#> 6 Q2 2007                 5064

关键注意事项与优化建议

  • 稳定性优先:尽量避免硬编码 XPath 路径或 CSS 类名。始终以页面上的用户可见文本(如标题)作为定位基准,这样即使底层样式微调,脚本也能保持较高的鲁棒性。
  • 错误防御:在生产脚本中,务必为关键步骤(如获取 `iframe_src` 和 `json_str`)添加 `tryCatch()` 逻辑,检查返回值是否为空,以应对网络波动或页面结构改版导致的意外中断。
  • 性能考量:启动 `chromote` 会话有一定开销。如果需要进行高频数据采集,建议复用浏览器会话,在完成所有任务后再关闭连接,而不是每次请求都重启浏览器。
  • 替代方案:`RSelenium` 是完成此类任务的另一个经典选择,但 `chromote` 通常更轻量,调试也更直观。如果需要跨平台部署,也可以考虑 `playwright`(可通过 R 包 `pwa` 调用)。
  • 合规提醒:数据采集务必遵守目标网站的 `robots.txt` 协议和服务条款。对于高频请求,请添加合理的延时,并考虑设置友好的 `User-Agent` 标识。

此方法的核心优势在于,它绕过了对复杂 JavaScript API 参数(例如某些建站平台动态生成的、带有大量参数的 API 链接)的逆向分析,直接针对最终的渲染结果进行提取。只要目标图表的标题和 iframe 的嵌套逻辑没有发生根本性改变,该脚本就能长期稳定工作,兼具鲁棒性和可维护性。

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章