基于RSelenium提取Facebook广告库内嵌Leaflet SVG底层数据的技术问询
解决Facebook广告库数据提取与规整问题
针对你用RSelenium爬取Facebook广告库时遇到的文本杂乱、图表/SVG数据提取困难的问题,我整理了几个实用的解决方案,一步步帮你搞定:
一、把杂乱文本规整为DataFrame
你现在直接抓取整个元素的文本导致数据混乱,核心思路是精准定位每个字段的DOM元素,逐个提取后再组合成结构化数据:
- 避免依赖动态变化的class名(Facebook的class经常更新),改用基于文本内容的XPath定位,比如找包含"投放时间""受众"等关键词的元素及其兄弟节点。
- 循环遍历所有广告详情页,提取每个字段后存入列表,最后转成DataFrame。
示例代码:
library(RSelenium) library(dplyr) library(stringr) # 初始化驱动(建议用chrome,稳定性更好) rs <- rsDriver(browser = "chrome") # 若需指定Chrome版本,可添加chromever参数 remote <- rs$client remote$navigate("https://www.facebook.com/ads/library/?active_status=all&ad_type=political_and_issue_ads&country=US&impression_search_field=has_impressions_lifetime&q=actblue&view_all_page_id=38471053686") # 先获取所有"查看广告详情"按钮(XPath可根据页面实际调整) ad_detail_buttons <- remote$findElements(using = "xpath", "//*[contains(text(), '查看广告详情')]") ad_data_list <- list() # 遍历每个广告详情 for(i in seq_along(ad_detail_buttons)){ # 点击详情按钮 ad_detail_buttons[[i]]$clickElement() Sys.sleep(2) # 等待页面加载 # 提取单个广告的各个字段(用tryCatch避免元素不存在报错) ad_title <- tryCatch( remote$findElement(using = "xpath", "//*[contains(@class, '_7lq0')]")$getElementText()[[1]], error = function(e) NA ) ad_run_dates <- tryCatch( remote$findElement(using = "xpath", "//*[contains(text(), '投放日期')]/following-sibling::div")$getElementText()[[1]], error = function(e) NA ) ad_impressions <- tryCatch( remote$findElement(using = "xpath", "//*[contains(text(), '展示次数')]/following-sibling::div")$getElementText()[[1]] %>% str_remove_all("[^0-9]") %>% as.numeric(), error = function(e) NA ) # 存入列表 ad_data_list[[i]] <- tibble( title = ad_title, run_dates = ad_run_dates, impressions = ad_impressions ) # 返回列表页 remote$goBack() Sys.sleep(2) # 重新获取按钮(页面刷新后原元素失效) ad_detail_buttons <- remote$findElements(using = "xpath", "//*[contains(text(), '查看广告详情')]") } # 转成结构化DataFrame ad_df <- bind_rows(ad_data_list)
二、提取图表(图片形式)的底层数据
Facebook广告库的图表看似是图片,其实大部分数据都藏在页面的script标签里的JSON中,不用OCR,直接解析即可:
- 找到包含图表数据的
script标签(通常包含"adImpressions""demographics"等关键词)。 - 用正则提取出JSON片段,再用
jsonlite解析成结构化数据。
示例代码:
library(jsonlite) # 在广告详情页中,找到包含受众年龄性别数据的script chart_script <- remote$findElement(using = "xpath", "//script[contains(text(), 'adImpressionsByAgeGender')]")$getElementText()[[1]] # 提取JSON部分(根据实际内容调整正则匹配规则) json_pattern <- "\\{\"adImpressionsByAgeGender\":.*?\\}" json_str <- str_extract(chart_script, json_pattern) # 解析JSON为结构化数据 chart_data <- fromJSON(json_str) # 转成DataFrame age_gender_df <- as.data.frame(chart_data$adImpressionsByAgeGender)
三、提取Leaflet SVG地图的底层数据
Leaflet地图的SVG元素会绑定数据到data-*属性,或者页面中存在对应的GeoJSON脚本,两种方式都可以提取:
方式1:从SVG元素的属性提取
library(rvest) # 获取SVG的完整HTML svg_html <- remote$findElement(using = "xpath", "//div[contains(@class, 'leaflet-container')]/svg")$getElementAttribute("outerHTML")[[1]] # 用rvest解析SVG节点 svg_doc <- read_html(svg_html) state_paths <- svg_doc %>% html_nodes("path") # 提取每个州的展示数据 map_data <- tibble( state_code = html_attr(state_paths, "data-state"), impressions = html_attr(state_paths, "data-impressions") %>% as.numeric() )
方式2:从页面的GeoJSON脚本提取
如果SVG的属性没有直接数据,找页面中存储地图数据的script标签:
map_script <- remote$findElement(using = "xpath", "//script[contains(text(), 'geoJsonData')]")$getElementText()[[1]] map_json_str <- str_extract(map_script, "\\{\"geoJsonData\":.*?\\}") map_geo_data <- fromJSON(map_json_str) # 转成包含地理属性的DataFrame map_df <- as.data.frame(map_geo_data$geoJsonData$features$properties)
四、实用注意事项
- 反爬机制:Facebook会检测频繁的自动化操作,建议每次操作后加
Sys.sleep(2-3),避免被限制访问。 - 动态class名:尽量用基于文本或元素结构的XPath,不要依赖固定的class(比如
_7kfh这种容易变动的命名)。 - 元素加载延迟:用
remote$waitForElement(using = "xpath", "你的XPath", timeout = 10)代替Sys.sleep(),更高效地等待元素加载完成。
内容的提问来源于stack exchange,提问作者Kim
相关产品推荐
相关产品推荐

