Zillow 爬虫教程:用 Python 提取房产数据

Zillow 坐拥互联网上最丰富的房地产数据集之一。价格、Zestimate 估价、上市天数、价格历史、经纪人联系方式。如果你从事房地产分析、潜在客户开发, 市场调研,或者只是想追踪你所在社区的房产价值, 这些数据值得放进电子表格里,而不是留在浏览器标签页中。
问题在于 Zillow 不希望你以程序化方式获取这些数据。该网站专门用于检测自动化流量,并会积极封锁。在本指南中,你将构建一个可用的 Python 抓取器,准确理解 Zillow 为何会进行反制,并了解要让抓取器在最初几次请求之后持续运行究竟需要什么。
到最后 你将拥有一个可用的 Zillow 抓取 Python 脚本 它会提取房产标题、地址、价格、卧室数、卫浴数、面积和房源 URL,并把所有内容写入一个 CSV 文件,你可以在 Excel 中打开它,或加载到 pandas 中。如果你一直在搜索如何抓取 Zillow 数据,或者想找一个简单直接的 Zillow 网页抓取器示例,那么它正是为成为这样的起点而打造的。
什么是 Zillow 抓取工具?
Zillow 抓取工具是一个脚本或程序,它可以 自动访问 Zillow 页面,读取嵌入在页面中的房源数据,并将其保存到有用的地方,通常是 CSV 文件、数据库或电子表格。
抓取工具无需手动从搜索结果中复制地址和价格,几秒钟就能完成,并且可以按天、按小时或按你设定的任何计划反复执行这一过程。
人们出于多种原因构建 Zillow 抓取工具:
- 房地产投资者 跟踪特定 ZIP 邮编区域内的降价信息和新房源
- 数据分析师 构建房地产市场模型或趋势报告
- 潜在客户开发机构 从经纪人房源中整理联系人名单
- 房产科技(Proptech)初创公司 将房源数据接入自己的应用程序
- 研究人员和学生 研究住房可负担性或价格趋势
- 开发者 构建租房或价格比较工具
这些使用场景都不需要进行任何破解。 这是公开的房源挂牌数据。挑战在于技术层面,而非概念层面:在不被 Zillow 的反爬虫系统拒之门外的情况下,可靠地获取页面内容。
你能抓取 Zillow 吗?
你能抓取 Zillow 吗?抓取 Zillow 合法吗?这是每个人在写下第一行代码之前都会问的问题,所以让我们诚实地讲清楚。
Zillow 的使用条款 未经许可,禁止从其网站自动采集数据。他们的 robots.txt 文件还限制了对网站大部分内容的抓取。这意味着,抓取 Zillow 违反了他们的平台规则,尽管根据美国法律,底层的房源数据(地址、价格、建筑面积)通常被视为公开信息。
网络抓取法律 这取决于司法管辖区、你收集哪些数据、如何使用这些数据,以及你是否访问了任何需要登录才能查看的内容。如果你是为了商业用途而进行抓取,尤其是涉及个人数据(例如代理商的联系方式)时,在扩大规模之前请先咨询律师。
通常能把一个合理、低风险的抓取项目与一个鲁莽的项目区分开来的因素:
- 开始之前先检查 robots.txt,并了解哪些路径是禁止爬虫访问的
- 只采集公开数据 无需登录即可查看
- 不要频繁猛烈地请求服务器。在请求之间加入延迟,而不是每分钟发出成百上千个请求
- 不要重新发布 Zillow 的专有数据 例如将 Zestimate 当作你自己的产品
- 尊重个人数据规则 如果你要采集经纪人的姓名、邮箱或电话号码,尤其是在 GDPR 或 CCPA 的监管下
- 将数据用于个人分析或内部研究 而不是搭建一个与之竞争的公开房源网站
每天都有大量的人为了个人项目、课程作业和内部市场调研而抓取 Zillow。
你能从 Zillow 抓取哪些数据?
Zillow 的房源页面和搜索结果承载了大量结构化数据。以下是前端通常可获取的内容:
| 数据字段 | 出现的位置 | Notes |
| 地址 | 搜索结果、房源页面 | 通常是完整的街道地址 |
| 价格 | 搜索结果、房源页面 | 当前挂牌价格 |
| Zestimate | 房源页面 | Zillow 自有的估价,与挂牌价格不同 |
| 卧室 / 卫生间 | 搜索结果、房源页面 | 数值 |
| 建筑面积 | 搜索结果、房源页面 | 居住面积,而非地块面积 |
| 地块面积 | 房源页面 | 对于公寓/单元房有时会缺失 |
| 房源状态 | 搜索结果 | 待售、交易中、已售、已下架 |
| 房源图片 | 房源页面 | 图片 URL,受版权保护 |
| Listing URL | 搜索结果 | 指向房源页面的直接链接 |
| 价格历史 | 房源页面 | 并非总是存在,取决于房源 |
| 经纪人姓名和经纪公司 | 房源页面 | 联系方式属于个人数据 |
| 在 Zillow 上挂牌的天数 | 搜索结果、房源页面 | 有助于追踪长期未售出的房源 |
在本教程中,我们将聚焦于大多数人真正需要的字段:标题、地址、价格、卧室数、卫浴数、面积和房源 URL。一旦抓取工具能处理这些字段,再增加几个字段只是小改动,而非重写。一个能处理这组核心字段的 Zillow 房产数据抓取工具,通常只需在解析步骤中添加新的键,就能扩展成完整的 Zillow 房源抓取工具。
用 Python 构建一个 Zillow 抓取工具
这是本指南的核心部分。我们将一步步从一个空文件夹,做到一个能导出 CSV 的可用抓取工具。
前置条件
您需要准备:
- Python 3.9 或更新版本
- 对终端有基本的熟悉度
- 一个代码编辑器(VS Code 就很好用)
- 大约 20 分钟
安装依赖项
我们让技术栈保持轻量: 用 requests 发起 HTTP 调用,用 beautifulsoup4 进行解析。请在虚拟环境中安装这两个库,以免它们与其他项目发生冲突。
lxml 是可选的,但它解析 HTML 的速度比 Python 内置的解析器更快,而 Zillow 的页面又很大。
项目搭建
先创建一个单独的文件作为开始。一旦它能正常运行,你就可以把它拆分成多个模块。
检查 Zillow 页面
在浏览器中打开一个 Zillow 搜索结果页面,右键点击,选择“查看页面源代码”(Windows 系统按 Ctrl+U)。 搜索 __NEXT_DATA__. 你会找到一个很大的 <script> 标签,其中包含一个 JSON 数据块,内含与页面上呈现的相同房源数据。

这一点很重要,因为这意味着你不必在数十个嵌套的 <div> 标签中费力翻找那些脆弱的 CSS 类。你可以直接提取 JSON,并从中读取干净、结构化的字段。这是现代基于 React 的网站上常见的模式,而且它比抓取可见的 HTML 稳定得多,因为可视化布局的变化频率远高于底层的数据结构。
Zillow 会定期更新其页面结构。此处所示的确切 script 标签 ID 或 JSON 结构可能会随时间变化。如果抓取工具无法再找到数据,请重新检查页面源代码,并调整解析逻辑以匹配当前实际存在的内容。
完整的 Python 抓取器
以下是完整脚本。我们随后会逐部分进行拆解讲解。
代码说明
下面说明每个部分实际的作用。
Headers. 该 build_headers() 函数会在一小组逼真的浏览器 user agent 之间轮换,并设置标准请求头,例如 Accept-Language。一个没有 user agent 的请求,或者一个明显伪造的请求,比如 python-requests/2.31,是最容易被标记的方式之一。
带退避机制的重试。 fetch_page() 以指数退避加上少量随机抖动重试失败的请求。这样可以避免以完全相同的间隔不断向 Zillow 的服务器发起重试,而这种固定间隔本身就是一种可被检测到的模式。
提取 JSON 数据。 extract_next_data() 查找 <script id=”__NEXT_DATA__”> 标签,并将其内容解析为 JSON。这比从带样式的可见文本中抓取数据要可靠得多 <div> 元素,因为 CSS 类名会不断变化,而底层的数据结构则更为稳定。
递归搜索房源。 parse_listings() 使用了一个递归辅助函数, find_results(),以遍历 JSON 树并找到 listResults 数组,无论它恰好位于何处。Zillow 的 JSON 结构将搜索状态嵌套了好几层,硬编码某一条确切路径往往会在他们上游做出任何改动时第一时间失效。
用于结构化的 Dataclass。 该 列表 dataclass 让每一行的结构保持一致,并使其可以轻松转换为字典,以便通过 asdict().
CSV 导出。 export_to_csv() 使用以下方式将每一条房源信息写出 csv.DictWriter导出为 CSV,字段名会自动从第一条房源的 dataclass 键中提取。
导出数据
运行该脚本会生成一个 zillow_listings.csv 文件位于你的项目文件夹中。每一行代表一处房产,可直接在 Excel、Google Sheets 中打开,或使用以下方式加载到 pandas DataFrame 中: pd.read_csv(“zillow_listings.csv”) 以供进一步分析。
示例输出
Improvements
上面的脚本刻意保持精简,方便你看清每个部分是如何运作的。一旦它开始运行,接下来你可以从这些方向继续拓展:
- Pagination. 通过调整 URL 中的 page 参数来遍历搜索结果页面,并在满足以下条件时停止 listResults 返回为空。
- 单个房源页面。 扩展抓取器,使其访问每个 listing_url 并从完整房源页面自身的数据中提取 Zestimate、价格历史和经纪人详情 __NEXT_DATA__ 封锁。
- 代理轮换。 将一个全新的代理传入 fetch_page() 在每次请求时都这样做,而不是在整个运行过程中重复使用同一个 IP。我们会在接下来的章节中详细说明原因。
- 一个真实的浏览器引擎。 如果 Zillow 在 JSON 数据加载之前开始返回 JavaScript 验证质询,请将 requests 换成 Playwright,它会像真实浏览器一样先渲染页面,然后再提取数据。
- 结构化日志记录。 记录每一个失败请求的状态码和 URL,这样你就能发现规律,比如某个特定的 ZIP 邮编或页码范围比其他情况触发更多封锁。
常见错误及其含义
- 403 Forbidden
Zillow 将该请求标记为自动化请求。通常是因为缺少或可疑的 user agent,或者来自同一 IP 的请求过多。
- 429 请求过多
你触发了速率限制。请放慢速度,并在请求之间添加更长的延迟。
- 未找到 __NEXT_DATA__
Zillow 返回的是 CAPTCHA 或验证页面,而不是真正的房源页面。请检查你收到的原始 HTML。
- JSONDecodeError
script 标签存在,但其内容的结构发生了变化。请打印原始字符串并手动检查。
为什么 Zillow 会拦截爬虫
Zillow 在反爬虫基础设施上投入巨大,值得你真正了解自己面对的是什么。
速率限制
在短时间内从同一个 IP 发送过多请求,就会 Zillow 会开始限速或直接封禁该 IP。真实用户不会在 10 秒内加载 50 个房源页面,所以这种模式会立刻显得很扎眼。
IP 信誉
Zillow 会检查 IP 地址的信誉度 发出请求。数据中心 IP,尤其是来自 AWS 或 DigitalOcean 等知名托管服务商的 IP,与机器人的关联性极强,被封锁的力度远比住宅 IP 更为激进。
浏览器指纹识别
除了 IP 之外,Zillow 的 反机器人层会检查 TLS 握手细节、请求头顺序以及 JavaScript 执行行为。一个普通的 requests 调用与真实的 Chrome 浏览器有着不同的指纹,而成熟的机器人检测能够察觉到这一差距。
CAPTCHA 验证挑战
当流量看起来可疑时,Zillow 会返回一个 返回 CAPTCHA 页面而非真实内容。Zillow 抓取时的 CAPTCHA 通常会在一连串快速请求或明显的机器人指纹之后出现。如果你的抓取程序没有处理这种情况,它会悄无声息地保存 CAPTCHA 页面而不是房源数据,这正是检查预期 JSON 结构如此重要的原因。
请求模式分析
请求之间保持一致、机械化的间隔时间,比如每两秒精确发起一次请求,本身就是一种信号。人类的浏览行为更为杂乱:会有停顿、回退,以及不固定的滚动速度。 随机化延迟很有帮助,但它们本身并不是一个完整的解决方案。
代理如何改善 Zillow 抓取
上述所有情况都指向同一个根本问题:你的 IP 地址是 Zillow 首先评估的对象,甚至早于它查看你的请求头或行为。
住宅代理 将你的请求通过互联网服务提供商分配给真实家庭的真实 IP 地址进行路由。在 Zillow 的系统看来,这些流量就像普通访客,而不是运行在云服务器上的抓取程序。
NodeMaven 的住宅代理来自一个覆盖 190 多个国家、超过 3000 万个真实且经过筛选的 IP 池,纯净 IP 率高达 95%。
在实际操作中,这对 Zillow 采集器有以下几方面帮助:
- 轮换 IP 会将你的请求分散到数千个不同的地址上,这样就不会有任何单个 IP 承受足够多的流量而被标记
- 更少的 CAPTCHA 验证挑战 因为干净的住宅 IP 比数据中心 IP 段引起的怀疑要少得多
- 粘性会话让你在多步骤流程中保持使用同一个 IP,比如翻遍某一次搜索的结果页,而无需在任务中途切换身份
- ZIP 邮编级别的地理定位 如果你正在抓取某个特定的本地市场,并希望获得与该地区匹配的 IP,这会很有用
- 每次请求的整体成功率更高,这意味着更少的重试次数以及从头到尾更快的采集速度
对于同时需要看起来像移动流量的抓取任务,或者需要访问对设备类型更敏感的端点的任务, 移动代理 也值得一试。

在将代理接入上面的抓取脚本之前,值得先验证一下连接是否按预期正常工作。 NodeMaven 的免费带宽检测工具 确认代理能否正常连接,并在抓取工作负载下表现得足够好,而 免费 IP 查询工具 能准确显示像 Zillow 这样的网站在另一端会看到什么样的 IP、位置和 ISP。两者都是免费的,且无需注册账户。
扩展您的 Zillow 抓取工具
一个能处理 50 条房源的脚本,在处理 50000 条时表现会大不相同。以下是规模扩大后会发生的变化。
重试与延迟
在请求之间加入随机延迟,而不是固定延迟。类似这样 time.sleep(random.uniform(2, 5)) 在两次页面抓取之间,看起来远不像每次都固定间隔两秒那样机械
轮换 IP
在大规模抓取时,手动切换代理凭据是行不通的。使用 轮换代理 这种设置会为每个请求或每个会话自动分配一个新 IP,让流量保持分散,而无需你手动管理
并发
顺序请求速度很慢。使用 concurrent.futures.ThreadPoolExecutor 或者使用异步库,例如 HTTPX 库 让你可以并行抓取多个页面。将并发数控制在适度范围内,5 到 10 个工作线程通常比 50 个更为稳妥
数据校验
并非每一条解析出的房源都是完整的。在写入一行数据之前,请对缺失的价格或地址字段进行检查,这样部分被拦截的响应就不会悄悄破坏你的数据集
日志记录
记录每个请求的 URL、状态码和时间戳。当定时任务在凌晨 3 点出问题时,正是这些日志能告诉你究竟是被拦截、解析结构变化,还是网络问题
Deduplication
Zillow 的房源可能会出现在多个搜索页面中,尤其是当你在抓取过程中有新房源导致分页发生变化时。请基于以下字段去重: zpid (Zillow 的内部房产 ID,可在房源 URL 中看到),而不要用地址文本,因为地址的格式可能会有所不同
自建抓取器的替代方案
编写自己的抓取工具并不是唯一的途径。根据你的时间安排和技术熟练程度,以下某种方式可能更适合你。
| 方法 | 最适合 | Tradeoffs |
| 自定义 Python 抓取工具 | 完全掌控、自定义字段、持续的内部使用 | 当 Zillow 更改其页面结构时,你需要对其进行维护 |
| Apify Zillow 抓取工具 | 快速设置,无需编写代码 | 基于用量的定价,输出格式的灵活性较低 |
| 房地产数据 API | 可靠、结构化的数据源 | 通常需要付费,可能无法涵盖你想要的每一个字段 |
| 开源 GitHub 项目 | 学习、快速原型开发 | 往往过时,当 Zillow 更新其网站时便会失效 |
| 浏览器扩展程序 | 一次性的小规模手动导出 | 并非为大规模或自动化而设计 |
Zillow 并未针对通用房源数据提供公开的 API。其官方 API 访问权限仅限于经过批准的合作伙伴,这也是为什么大多数开发者最终选择抓取公开网站的原因。
结论
一旦你理解了各个环节,用 Python 构建一个 Zillow 抓取工具就是一个可以在周末完成的项目:获取页面、提取内嵌的 JSON、将其解析为清晰的结构,然后导出。更难的部分是让这个抓取工具稳定持续地运行,而这取决于你的请求在 Zillow 的反爬虫系统看来是什么样子。
逼真的请求头、合理的延迟以及纯净的住宅 IP,能解决你会遇到的大多数稳定性问题。请负责任地抓取,尊重速率限制,并让你的使用方式与数据的实际用途保持一致。
如果拖慢你速度的是 IP 封锁,那么 NodeMaven 的 住宅代理 和 移动代理 值得在你大规模扩展之前,先用你自己的爬虫进行测试。



