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

使用Selenium和BeautifulSoup爬取Airdna地图标记悬停窗口数据

问题原因
  • 选择器错误:你使用的Page__RightColumn-sc-291lxm-3是页面右侧内容栏的容器类,根本不是地图标记的类,自然获取不到任何元素。
  • 动态类失效:这类站点使用CSS Module生成带随机哈希后缀的类名(比如带sc-xxx的格式),类名会随版本更新变化,硬写死的类名大概率失效。
  • 地图元素懒加载:地图标记是动态渲染的,只有出现在当前地图视口范围内的标记才会被插入DOM,视口外的标记不会提前生成。
解决方法

方案1:直接抓取接口(更稳定)

Airdna的地图标记数据都是通过接口提前加载的,你可以打开浏览器控制台的「网络」标签,筛选Fetch/XHR请求,找到返回房产列表的接口,直接请求接口拿数据,不需要模拟点击操作,稳定性高很多,也不会遇到DOM元素找不到的问题。

方案2:修改Selenium代码适配DOM结构

代码调整点:

  1. 替换正确的标记选择器:优先用不带动态哈希的通用类,比如Leaflet地图库的标记通用类leaflet-marker-icon,或者通过属性筛选包含房产标识的元素。
  2. 增加显式等待:不要依赖手动输入暂停,用WebDriverWait等待元素渲染完成再操作。
  3. 避免元素过期错误:点击标记后DOM会更新,原来的标记元素引用会失效,不要直接遍历首次获取的标记列表,每次操作后重新获取标记列表。
  4. 修正数据存储格式:原代码中用{}存储两个值会生成集合而非字典,需要指定key。

修改后的参考代码:

from bs4 import BeautifulSoup
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.action_chains import ActionChains
import time

driver = webdriver.Chrome()
driver.get("https://www.airdna.co/vacation-rental-data/app/us/california/santa-monica/overview")
driver.maximize_window()

# 等待引导关闭,手动操作完后程序继续
input("请手动关闭页面引导、完成验证后按回车继续...")

target_list = []
wait = WebDriverWait(driver, 10)

try:
    # 等待地图标记加载完成
    wait.until(EC.presence_of_all_elements_located((By.CSS_SELECTOR, "img.leaflet-marker-icon")))
    # 第一次获取所有标记
    mapMarkers = driver.find_elements(By.CSS_SELECTOR, "img.leaflet-marker-icon")
    
    for idx in range(len(mapMarkers)):
        # 每次重新获取标记避免元素过期
        current_marker = driver.find_elements(By.CSS_SELECTOR, "img.leaflet-marker-icon")[idx]
        # 滚动到标记可见
        driver.execute_script("arguments[0].scrollIntoViewIfNeeded();", current_marker)
        time.sleep(1)
        
        # 悬停触发弹窗(部分标记是悬停触发而非点击)
        ActionChains(driver).move_to_element(current_marker).pause(2).perform()
        
        # 等待弹窗加载
        wait.until(EC.presence_of_element_located((By.CLASS_NAME, "info-window__statistics-value")))
        
        html = driver.page_source
        soup = BeautifulSoup(html, "lxml")
        
        days = soup.find_all("p", class_="info-window__statistics-value")
        link = soup.find_all("a", class_="info-window__property-link")
        if days and link:
            target_list.append({
                "days_available": days[0].text.strip().replace('\n', '').replace(' ', ''),
                "property_link": link[0].attrs['href']
            })
        # 点击空白处关闭弹窗
        ActionChains(driver).move_by_offset(100, 100).click().perform()
        time.sleep(1)
        
except Exception as e:
    print(f"运行出错:{e}")
finally:
    driver.quit()
    # 输出结果
    for item in target_list:
        print(item)

额外注意事项:

  • 该站点有反爬机制,频繁操作会触发验证码,建议操作之间增加随机延迟,必要时使用代理IP。
  • 地图仅渲染当前视口内的标记,如果需要抓取全量数据,需要模拟拖动地图加载更多区域的标记。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.01 06:15:03