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

R语言rvest批量提取多类class网页卡片元素及属性方法

fotocasa.es房源爬虫全量卡片抓取方案

场景说明

抓取fotocasa.es房源列表页的链接、标题等信息时,最初通过匹配re-CardPackMinimal-info-container类提取链接仅返回27条结果,与页面实际30条房源的数量不符。排查发现列表内的卡片分属多个class:re-CardPackMinimal(普通房源)、re-AdvertisingNativeListing-container/re-AdvertisingTop2Listing(广告)、re-CardPackPremium(Premium房源)、re-CardPackAdvance(Advance房源)。手动逐个指定class选节点的方式维护成本高,需要实现两个目标:

  • 无需手动枚举class,自动抓取所有卡片的全量字段
  • 提取结果可区分普通房源、广告、不同等级付费房源类型

现有基础代码

已通过rvest、tidyverse、xml2、RSelenium实现页面打开、cookie同意、排序、滚动加载全流程,可拿到完整渲染后的页面源码:

library(rvest)
library(tidyverse)
library(xml2)
library(stringr)
library(RSelenium)

openAndScrollPage <- function(link){
  driver = rsDriver(browser = c("firefox"))
  remDr <- driver[["client"]]
  remDr$navigate(link)
  
  # 同意cookie
  remDr$findElement(using = "xpath", '/html/body/div[1]/div[4]/div/div/div/footer/div/button[2]')$clickElement()
  
  # 按最新排序
  remDr$findElement(using = 'xpath', '//*[@id="App"]/div[2]/div[1]/main/div/div[3]/div/div/select/option[3]')$clickElement()
  
  # 逐段滚动加载全部内容
  for(i in 1:30){ 
    print(paste("Scrolling for: ", i, " seconds", sep = ""))
    remDr$executeScript("window.scrollBy(0,500);")
    Sys.sleep(1)
  }
  # 读取完整页面源码
  html_full_page = remDr$getPageSource()[[1]] %>% 
    read_html()
  return(html_full_page)
}

link2 = "https://www.fotocasa.es/es/comprar/viviendas/barcelona-capital/la-nova-esquerra-de-l-eixample/l"
page2 = openAndScrollPage(link2)

已验证可通过如下代码拿到所有卡片的class属性,共返回30+节点(含2个广告节点):

page2 %>% 
  html_nodes(".re-SearchResult") %>% 
  html_children() %>%
  html_attr(name = "class")

返回结果示例:

[1] "re-CardPackMinimal"                    "re-CardPackMinimal"                    "re-CardPackMinimal"                   
 [4] "re-CardPackMinimal"                    "re-AdvertisingTop2Listing"             "re-CardPackMinimal"                   
 [7] "re-CardPackMinimal"                    "re-CardPackMinimal"                    "re-CardPackMinimal"                   
[10] "re-AdvertisingNativeListing-container" "re-CardPackMinimal"                    "re-CardPackMinimal"                   
[13] "re-CardPackMinimal"                    "re-CardPackMinimal"                    "re-CardPackMinimal"                   
[16] "re-CardPackMinimal"                    "re-CardPackMinimal"                    "re-CardPackMinimal"                   
[19] "re-CardPackMinimal"                    "re-CardPackMinimal"                    "re-CardPackMinimal"                   
[22] "re-CardPackMinimal"                    "re-CardPackMinimal"                    "re-CardPackPremium"                   
[25] "re-CardPackPremium"                    "re-CardPackMinimal"                    "re-CardPackMinimal"                   
[28] "re-CardPackMinimal"                    "re-CardPackAdvance"                    "re-CardPackMinimal"                   
[31] "re-CardPackMinimal"                    "re-CardPackMinimal"

解决方案

不用提前枚举class做批量匹配,直接选中.re-SearchResult下所有子节点就是全部房源卡片,提取单卡片信息时同步记录节点class作为类型标识即可,不会漏数。

可直接运行的实现代码

# 提取搜索结果容器下所有卡片节点,覆盖所有class类型
all_cards <- page2 %>% 
  html_element(".re-SearchResult") %>% 
  html_children()

# 批量提取全字段,自动标记卡片类型
house_data <- tibble(
  # 记录卡片原始class值
  raw_card_class = html_attr(all_cards, "class"),
  # 归类卡片类型
  card_type = case_when(
    str_detect(raw_card_class, "Advertising") ~ "广告",
    str_detect(raw_card_class, "Premium") ~ "Premium付费房源",
    str_detect(raw_card_class, "Advance") ~ "Advance付费房源",
    str_detect(raw_card_class, "Minimal") ~ "普通房源",
    TRUE ~ "未知类型"
  ),
  # 提取房源详情链接,兼容所有卡片的链接结构
  detail_url = map_chr(all_cards, function(node){
    node %>% 
      html_node("a[href^='/es/comprar/vivienda/'], a[href^='/vivienda/']") %>% 
      html_attr("href") %>% 
      paste0("https://www.fotocasa.es", .)
  }),
  # 提取房源标题,兼容不同卡片的标题class
  title = map_chr(all_cards, function(node){
    node %>% 
      html_node("[class*='title']") %>% 
      html_text(trim = T)
  })
)

逻辑说明

  • 选节点时直接取搜索结果容器的所有直接子节点,不需要提前收集class再逐个匹配,天然覆盖所有卡片类型,不会漏数
  • 类型判断直接基于卡片自身的class属性,自动区分广告、不同等级付费房源、普通房源
  • 单卡片内的字段提取用模糊匹配的选择器,兼容不同类型卡片的内部结构差异,不需要给每类卡片单独写提取规则
  • 如果后续需要提取价格、面积、房间数等其他字段,直接在tibble里加对应列,用同样的节点内匹配逻辑即可

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 13:39:18