返回博客
指南
Raluca PenciucLast updated on May 8, 20262 min read

如何抓取 Realtor.com:2026 年实用指南

如何抓取 Realtor.com:2026 年实用指南
简而言之:如果你正在研究如何干净利落地抓取Realtor.com的数据,有三点至关重要:能够应对哈希类名的稳定选择器、能突破Realtor反机器人防护机制的请求层,以及既能遍历列表页面又能遍历详情页面的代码。本指南提供了完整的Python实现方案,包含反封锁策略和适用于大型语言模型(LLM)的导出格式。

若需大规模获取房产数据,掌握如何抓取 Realtor.com 是您能习得的高效技能之一。Realtor.com 是美国主要房地产交易平台,提供待售房源、租赁房源及实时房产市场信息,其中大部分数据以 HTML 形式呈现,可通过 Python 进行解析。

难点在于,Realtor.com 作为高价值目标,部署了严密的反机器人防护体系。简单的 requests.get() 调用会返回 CAPTCHA HTML,哈希类名会无预警轮换,而最丰富的字段则隐藏在嵌入的 JSON 数据块中。如果工具链选择不当,可能耗费一周时间也无法产出一条干净的数据行。

本指南将带您完整了解 Python 抓取流程的端到端操作:哪些字段可以实际提取、哪些选择器能突破 Realtor.com 的 React 渲染机制、如何通过能自动处理代理和 CAPTCHA 的抓取 API 路由请求,以及如何提取房产详情页中的数据(如经纪人联系方式、配套设施和经纬度)。 我们将涵盖流量控制、错误处理、法律限制,以及如何将房源数据输入大语言模型(LLM)进行后续分析。

最终您将获得一个可运行的爬虫程序,而非仅是复制粘贴的代码片段——后者在前端更新后往往会失效。

为何要抓取 Realtor.com 以及哪些团队会利用这些数据

掌握 Realtor.com 抓取技术将开启一系列实用的应用场景。投资团队会提取房源信息用于可比房产分析和自动估值模型(AVM)训练。经纪公司则致力于潜在客户开发,力求在竞争对手之前发现已过期或重新挂牌的房产。 市场研究人员按邮政编码追踪房源库存和价格趋势。房地产科技工程师将房源数据导入 LLM 管道进行信息增强。这些场景的共同点在于:Realtor.com 的房源信息持续更新,因此手动收集在处理少量房源后便难以维系,而结构化抓取是唯一能跟上节奏的合理方式。

Realtor.com 中实际可提取的数据字段

大多数教程仅介绍六个字段。但若同时抓取搜索结果和详情页,可提取的信息将远不止于此。在搜索结果卡片中,可靠的字段包括挂牌价、完整地址、卧室数、浴室数、建筑面积、地块面积、挂牌状态以及详情页的标准 URL。

点击每个详情页链接,可提取以下信息:

  • 房产基本信息:建成年份、房产类型、业主协会费、停车位、地块尺寸
  • 配套设施:供暖、制冷、地面材料、家电、外观特征
  • 地理位置:经纬度(便于地图绘制和邮编级别的关联)
  • 媒体:来自房源图库的图片 URL
  • 经纪人:经纪人姓名、电话号码及所属经纪公司
  • 房源元数据:MLS ID、在市天数、价格历史

这套数据集不仅包含价格和地址信息,更是支撑比价分析、潜在客户列表和自动估值模型(AVM)的核心数据。

Realtor.com的反机器人防御体系:你将面临的实际挑战

在编写爬虫代码之前,请先了解你将面临的挑战。Realtor.com运行着一套行为反机器人防护系统,其功能远超IP封禁。逆向工程报告指出,该防护系统采用的是Kasada级别的指纹识别技术;无论Kasada是否仍是当前的供应商,其检测信号在反机器人防护领域已有充分记录。

若想以有效规模抓取Realtor.com数据,需重点关注以下三个层面:

  1. TLS 和 JS 指纹识别。普通的 Python requests 生成的 TLS 握手和头部顺序与真实浏览器不符,Realtor.com 的边缘防护系统可在首次访问时就将其标记。
  2. 行为关联分析。鼠标熵代理、滚动模式及 DOM 交互信号会与人类行为分布进行比对。若爬虫从单一 IP 地址疯狂抓取页面,其行为模式与人类完全不符。
  3. 验证码页面。当评分超过阈值时,页面主体会变成验证码页面而非房源列表,通常返回 200 状态码,因此简单的爬虫甚至无法察觉失败。

请从项目伊始就为这三点做好准备,而不是在抓取到第一批空行后才仓促补救。

为您的项目选择合适的抓取方案

关于如何抓取Realtor.com,虽无唯一标准答案,但有三种方案值得了解,且各适用于不同的使用场景。

方法

最适合

优缺点

requests + 爬取API

后端管道、生产环境数据任务

如果您的 API 支持 JS 渲染和代理,则速度最快且成本最低

搭配 undetected-chromedriver 的 Selenium

需要真实浏览器交互或登录流程的页面

每页成本较高,难以扩展,且长期使用仍会遇到验证码

无代码可视化爬虫

分析师临时抓取几百条列表

类名变更时易受影响;不适合定时运行的管道

快速建议:如果您是正在构建定期数据源的 Python 团队,请使用 requests 配合爬取API,并使用BeautifulSoup解析HTML——本指南正是如此操作。仅当确实需要与登录状态下的页面或高度依赖JS的视图交互时,才使用无头浏览器;将无代码可视化爬虫视为一次性辅助工具,而非生产环境的基础设施。

先决条件与项目设置

在深入探讨如何端到端抓取 Realtor.com 之前,请先搭建一个干净的环境。你需要 Python 3.9 或更高版本、一个全新的虚拟环境,以及四个包:

python -m venv .venv && source .venv/bin/activate
pip install requests beautifulsoup4 lxml pandas

此外,你还需要一个爬取 API 密钥。本指南将使用 WebScrapingAPI 作为请求层;请注册账号,从仪表盘复制密钥,并将其存储为环境变量,确保它不会被提交到 Git:

export WSA_KEY="your_key_here"

配置工作就到此为止。无需浏览器驱动程序,也无需费心管理代理列表。

如何使用 Python 逐步抓取 Realtor.com

接下来我们将通过五个关键步骤构建实际的爬虫程序:检查 DOM 并确定稳定的选择器、通过爬取 API 获取搜索页面、使用 BeautifulSoup 解析房源卡片、遍历分页结果,以及导出为 JSON、CSV 或 pandas DataFrame。下文的代码块均基于上一节的配置。

检查房源并映射 CSS 选择器

在 Chrome 中打开 Realtor.com 的搜索结果,右键点击一个房源卡片,选择“检查”。每个卡片都被包裹在 <li> 标签中,并包含 data-testid="result-card"标签包裹。价格、地址和元数据字段位于 <div>标签内,而 <li>标签中,这些标签带有各自的 data-label 属性(pc-price, pc-address, pc-meta-beds等)。

Realtor.com 还会将每张卡片与一个哈希类(如 BasePropertyCard_propertyCardWrap__abc123请勿根据哈希值进行筛选。这些后缀会在每次前端构建时重新生成,且会毫无预兆地导致您的抓取程序失效。请以 data-testiddata-label 属性。这些属性是专门为前端自身的测试而存在的,因此是您最稳定的锚点。

通过 WebScrapingAPI 抓取搜索页面

完成选择器映射后,将实际请求通过爬取 API 进行路由。该 API 会自动处理住宅代理轮换、JS 渲染和 CAPTCHA 验证,因此您的代码可以专注于解析工作。

import os, requests

WSA_KEY = os.environ["WSA_KEY"]
SEARCH_URL = "https://www.realtor.com/realestateandhomes-search/Cincinnati_OH"

def fetch(url: str) -> str:
    r = requests.get(
        "https://api.webscrapingapi.com/v2",
        params={
            "api_key": WSA_KEY,
            "url": url,
            "render_js": "1",
            "country": "us",
        },
        timeout=60,
    )
    r.raise_for_status()
    return r.text

html = fetch(SEARCH_URL)

为何要专门通过 Realtor.com 的 API 进行请求?因为普通的 requests.get 在几次请求内就会触发验证码页面,因为其 TLS 指纹和头部顺序与真实浏览器不符。该 API 会为您规范这两项,并按每次请求轮换住宅 IP。

使用 BeautifulSoup 解析房源卡片

获取 HTML 后,BeautifulSoup 会将其转换为可供查询的数据。请采取防御性策略:并非每张卡片都包含所有字段,因此需对每次查询进行保护,以免因缺少单个地块面积字段而导致整行数据报错。

from bs4 import BeautifulSoup

def parse_cards(html: str) -> list[dict]:
    soup = BeautifulSoup(html, "lxml")
    cards = soup.select('li[data-testid="result-card"]')
    listings = []
    for card in cards:
        def text(sel):
            el = card.select_one(sel)
            return el.get_text(strip=True) if el else None
        link = card.select_one("a[data-testid='card-link']")
        listings.append({
            "price":    text('[data-label="pc-price"]'),
            "address":  text('[data-label="pc-address"]'),
            "beds":     text('[data-label="pc-meta-beds"] span'),
            "baths":    text('[data-label="pc-meta-baths"] span'),
            "sqft":     text('[data-label="pc-meta-sqft"] span'),
            "lot_size": text('[data-label="pc-meta-sqftlot"] span'),
            "url": link["href"] if link and link.has_attr("href") else None,
        })
    return listings

我们将使用 url 字段跳转至各房源的详情页。若您希望更深入地使用 BeautifulSoup,我们的 Python BeautifulSoup 解析指南将是极佳的参考资料。

遍历分页结果

Realtor.com 采用 /pg-N URL 模式实现分页,每页结果约返回 42 张房源(具体数量会波动,因此请勿将其作为终止条件)。最稳健的策略是将页码计数器与空结果检查相结合:

def scrape_search(base_url: str, max_pages: int = 10) -> list[dict]:
    all_listings = []
    for page in range(1, max_pages + 1):
        page_url = base_url if page == 1 else f"{base_url}/pg-{page}"
        cards = parse_cards(fetch(page_url))
        if not cards:
            break
        all_listings.extend(cards)
    return all_listings

当某页返回零条房源时停止,远比依赖任何固定的每页条数更安全。

将结果导出为 JSON、CSV 或 DataFrame

收集完房源列表后,将其导入 pandas 进行去重,并按所需格式导出。详情页 URL 是每个房源最稳定的唯一标识符。

import pandas as pd

df = pd.DataFrame(scrape_search(SEARCH_URL))
df = df.drop_duplicates(subset="url").reset_index(drop=True)

df.to_json("realtor_listings.json", orient="records", indent=2)
df.to_csv("realtor_listings.csv", index=False)

CSV是导入Excel和BI工具的最简便途径。若下游代码需要处理嵌套对象(特别是在我们添加详情页字段后),JSON会更合适。无论采用哪种格式,导出前都应进行去重,因为Realtor.com有时会在相邻的搜索页面中重复显示同一房源。

抓取单个房源详情页

详情页包含更丰富的数据集:建成年份、配套设施、经纪人联系方式、经纬度、照片。Realtor.com 嵌入了两个结构化数据包:

  1. 一个 <script type="application/ld+json"> 块,遵循 schema.orgRealEstateListing 词汇表。
  2. 一个 <script id="__NEXT_DATA__"> 包含完整房产记录的数据包(Next.js 数据加载对象)。

两者均为 JSON 格式:

import json
from bs4 import BeautifulSoup

def parse_detail(html: str) -> dict:
    soup = BeautifulSoup(html, "lxml")
    raw  = soup.find("script", id="__NEXT_DATA__").string
    prop = json.loads(raw)["props"]["pageProps"]["initialReduxState"]["propertyDetails"]
    coord = (prop.get("location", {}).get("address", {}).get("coordinate") or {})
    adv   = (prop.get("advertisers") or [{}])[0]
    return {
        "year_built": prop.get("description", {}).get("year_built"),
        "lat": coord.get("lat"), "lon": coord.get("lon"),
        "amenities": prop.get("description", {}).get("features", []),
        "agent_name":  adv.get("name"),
        "agent_phone": (adv.get("phones") or [{}])[0].get("number"),
        "brokered_by": adv.get("office", {}).get("name"),
        "photos": [p["href"] for p in (prop.get("photos") or [])],
    }

该键路径会发生漂移;在开发过程中请记录原始有效载荷,并在发现 KeyError。JSON-LD 更稳定,但暴露的字段较少。

将房地产经纪人房源信息转化为适合 LLM 处理的数据

一旦获得干净的房源 JSON,使用 LLM 是丰富数据的最快途径。跳过“总结本页”的模式;按房源分块,并使用结构化提示词。

两条高回报的处理路径:

  • 比价分析。将同一邮编区域的五到十个房源作为单个提示输入,配合 JSON 模式,要求输出调整后的每平方英尺价格、住宅类型匹配结果及异常值标记。一次交互即可获得比价报告。
  • 潜在客户信息增强。将经纪人姓名、经纪公司及房源链接输入模型,模型将返回包含可信度评分的标准化联系人卡片。

通过爬取 API 将页面以 Markdown 格式而非 HTML 格式提取,可将令牌成本大致减半。

规避封禁:代理、请求头与流量控制

若使用数据中心 IP 并采用默认头部信息抓取 Realtor.com,您将遭到封禁。除了抓取 API 为您处理的内容外,真正能起作用的缓解措施包括:

  • 住宅代理。数据中心 IP 容易被批量标记;使用住宅代理轮换可使流量看起来像真实访客。
  • 标头轮换。随机化 User-Agent, Accept-Language,并 Sec-Ch-Ua 按请求随机化,并保持一致性(iPhone 用户代理搭配 Windows 平台标头会立即暴露身份)。
  • 流量控制。请求间隔保持约三到六秒的抖动,可使行为模式低于大多数平台的阈值。
  • 指数退避。遇到 403 或 429 状态码时,暂停 2 ** attempt + random.random() 并轮换会话;切勿通过同一连接重试。

自己构建所有这些功能是一项大工程;大多数团队都会将其外包。

法律和道德考量

Realtor.com 的房源页面是公开的,因此为内部研究收集价格、地址和结构字段通常是站得住脚的,但这并不意味着可以为所欲为。在构建定期数据采集管道之前,请阅读 Realtor.com 的《使用条款》robots.txt。根据加利福尼亚州《消费者隐私法案》CCPA)及类似法规,应将经纪人姓名、电话号码和电子邮件视为个人数据;若为转售或未经请求的推广而收集这些信息,将使您陷入受监管的领域。

排查常见的Realtor数据抓取错误

Realtor 爬虫的大多数错误可归因于以下五种故障模式:

  • 房源列表为空。您当前看到的可能是返回 200 状态码的验证码页面;请检查页面标题,然后在 API 端开启 JS 渲染。
  • 哈希类偏移。将任何 BasePropertyCard_propertyCardWrap__* 选择器替换为 data-testiddata-label lookup。
  • 403 / 429 错误激增。延长重试间隔,轮换会话,并仅在错误率稳定后才增加并发量。
  • 缺少详细字段。 __NEXT_DATA__ 键路径已移动;请记录原始有效载荷并重新固定键。
  • 重复行。导出前务必在列表 URL 上进行去重。

关键要点

  • 优先处理选择器,其次处理请求。data-testiddata-label 属性,切勿基于 BasePropertyCard_propertyCardWrap__*,因为这些会在每次前端构建时重新生成。
  • 生产环境中请通过爬取 API 进行路由。普通的 requests 在几次调用内就会触发Realtor.com上的验证码页面;而API层能在一跳之内处理代理、JS渲染和TLS指纹识别。
  • 详情页的数据量是原始数据集的10倍。建造年份、配套设施、经纪人联系方式以及经纬度都存储在 __NEXT_DATA__ 每个房源页面的 blob 和 JSON-LD 中,而非搜索结果卡片中。
  • 即使使用优质 API,也需实施限流和退避策略。通过约 3 至 6 秒的抖动时间、住宅数据轮换以及针对 403/429 状态码的指数退避,可确保长期运行的管道保持稳定。
  • 遵守法律框架。房源数据属于公开信息;经纪人联系方式属于个人数据。扩展前请仔细阅读条款,并避免转售受监管字段的数据。

常见问题

Realtor.com 是否提供官方 API 供我使用,以替代数据抓取?

目前不存在用于浏览房源的通用公共 API。Realtor.com 的母公司历来通过 MLS 数据源提供 RETS 和 RESO Web API 访问权限,但这些接口需通过经纪人或合作伙伴协议获取,而非开放给开发者注册。对于大多数独立开发者和分析师而言,对公共房源页面进行结构化抓取仍是获取批量数据的唯一可行途径。

Realtor.com 会屏蔽来自 AWS、GCP 或其他数据中心 IP 的请求吗?

是的,几乎会立即封禁。Realtor.com 的反机器人系统维护着主要云服务提供商 ASN 的黑名单,并会对其实施严格的速率限制或强制验证。在普通 EC2 或 Cloud Run 实例上运行的爬虫,仅需几次请求就会遇到 CAPTCHA 验证页面。您需要使用住宅代理或移动代理,或者采用能透明处理 IP 轮换的爬取 API。

抓取 Realtor.com 与抓取 Zillow 或 Redfin 有何不同?

这三者均采用 React 渲染、分页显示,并受到基于行为的反机器人系统的保护,但具体实现细节各不相同。Zillow 高度依赖其 __NEXT_DATA__ 有效负载,并会积极进行移动设备指纹检测。Redfin则公开了其前端使用的更丰富的内部JSON API。Realtor.com介于两者之间:卡片上稳定的 data-testid 卡片上的钩子,外加 __NEXT_DATA__ 详情页上的 blob。

当 Realtor.com 更改其哈希类名时,如何确保爬虫继续正常工作?

首先,不要依赖哈希类名。将每个选择器锚定在 data-testiddata-label 属性上,这些是前端自身测试契约的一部分,极少发生变化。添加一个烟雾测试,每天早晨抓取一个已知的房源,并验证价格字段不为空;若测试失败则发出警报,以便在数据管道悄然清空之前重新固定选择器。

对于长期运行的 Realtor.com 爬虫,安全的请求频率是多少?

一个有用的起始范围是:每个会话中请求间隔约三到六秒的随机延迟,同时保持一到三个并发会话,且每个会话使用不同的住宅IP。密切关注403/429错误率;如果一小时内的错误率超过一到两个百分点,则应进一步降低请求频率或更频繁地轮换代理。突发流量比稳定流量更容易被标记。

结论

掌握 Realtor.com 的端到端抓取,关键在于按正确顺序分层构建:锁定稳定的选择器,通过能代为处理反机器人机制的组件路由请求,追踪房源链接进入详情页获取剩余数据集,并在导出前进行去重。只要这些环节处理得当,您构建的管道就能在下次前端重构时安然无恙,而非因此崩溃。

住宅房源轮换、JS渲染、验证码处理等难点,正是团队若自行开发会耗费数周时间的环节。这些环节也最适合委托给托管请求层处理,从而让您的工程师能够专注于数据解析、建模和下游分析。

如果您不愿自行运维代理集群、头部生成器和验证码破解器,WebScrapingAPI 提供的 Scraper API 正是为此类任务而设计:它能针对您指定的任意 URL 返回渲染后的 HTML,自动处理 403/429 状态码的重试请求,并轮换来自 195 个国家的住宅 IP,使您的爬虫看起来就像 200 位不同的用户正在浏览辛辛那提的房源信息。 将其集成到上述构建中,您需要维护的代码仅剩解析层。

关于作者
Raluca Penciuc, 全栈开发工程师 @ WebScrapingAPI
Raluca Penciuc全栈开发工程师

Raluca Penciuc 是 WebScrapingAPI 的全栈开发工程师,主要负责开发爬虫、优化规避机制,并探索可靠的方法以降低在目标网站上的被检测概率。

开始构建

准备好扩展您的数据收集规模了吗?

加入2,000多家企业,使用WebScrapingAPI在无需任何基础设施开销的情况下,以企业级规模提取网络数据。