如何抓取房地产数据:完整指南
从网站上抓取房地产数据是一项独特的挑战。房地产网站使用 JavaScript 渲染、动态内容加载和反僵尸措施来阻止传统的抓取工具。本指南涵盖实用的解决方案,使用 Python 和 Bright Data公司的工具.
请注意: 我与 Bright Data 没有任何关系。这是我最熟悉的平台,因此我选择在这里使用它。
为什么房地产搜索具有挑战性?
房地产网站存在三大障碍:
1.摘要页与详细页
搜索结果显示的数据有限(价格、地址、缩略图)。完整的房产详细信息--平方英尺、房产历史、代理信息--需要访问单个列表页面,这就成倍增加了所需请求的数量。
2.JavaScript 渲染
大多数房地产平台在客户端呈现内容。基本 HTTP 请求会返回不完整的 HTML,因为数据是在初始页面加载后通过 JavaScript 加载的。
3.反僵尸保护
网站采用 IP 过滤、验证码、速率限制和浏览器指纹识别来检测和阻止刮擦程序。
带请求和 BeautifulSoup 的基本爬虫
这种方法适用于没有大量反僵尸措施的简单网站。
检查目标页面
在编写代码之前,请检查页面结构:
- 在浏览器中打开搜索结果
- 右键单击物业列表,选择 "检查
- 确定包含所需数据(价格、地址、链接)的 HTML 元素
安装
pip install requests beautifulsoup4
基本爬虫代码
import requests
from bs4 import BeautifulSoup
import csv
url = "https://www.example.com/homes/for_sale/San-Francisco/"
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"
}
response = requests.get(url, headers=headers)
if response.status_code == 200:
soup = BeautifulSoup(响应内容) html.parser)
结果 = []
property_items = soup.find_all("li", {"data-testid": "财产卡"})
for item in property_items:
try:
地址 = item.find("address").get_text(strip=True)
price = item.find("span", {"数据测试": "房产证价格"}).get_text(strip=True)
url_link = item.find("a").get("href")
full_url = f "https://www.example.com{url_link}" if url_link 和 not url_link.startswith("http") else url_link
if 地址 或 价格
results.append({
"address"地址
"price"价格、
"link": full_url
})
except Exception as e:
print(f "卡片解析出错: {e}")
if results:
with open("real_estate_data.csv", "w", newline="", encoding="utf-8") as f:
writer = csv.DictWriter(f, fieldnames=[)"address", "price", "link"])
writer.writeheader()
writer.writerows(results)
print(f "Scraped {len(results)} 上市")
else:
print(f "获取页面失败。状态代码: {response.status_code}")
限制: 在使用 JavaScript 渲染或反僵尸保护的网站上,这种方法会失效。
用Bright Data处理反僵尸措施
当基本搜索失败时,Bright Data 可根据您的需求提供多种解决方案。
选项 1:解锁 API(建议用于静态页面)
解锁程序接口处理 代理轮换, 解决验证码问题以及自动绕过反僵尸程序。您只需发送一个请求,它就会返回干净的 HTML 或 JSON。
最适合
- 不需要浏览器交互的页面
- 大批量刮削,成本可预测
- 没有代理基础设施的团队
直接访问 API(推荐方法)
导入请求
API_KEY = "YOUR_API_KEY"
ZONE_NAME = "您的区域名称"
headers = {
"Authorization": f"承载器 {API_KEY}",
"内容类型": "application/json"
}
有效载荷 = {
"区":ZONE_NAME、
"url": "https://www.example.com/homes/for_sale/San-Francisco/",
"格式": "原始"
}
response = requests.post(
"https://api.brightdata.com/request",
headers=headers、
json=payload
)
if response.status_code == 200:
html_content = response.text
# 使用 BeautifulSoup 进行解析
soup = BeautifulSoup(html_content, 'html.parser')
# 如上图所示提取数据
基于本地代理的访问
对于已经使用代理路由的工作流程:
import 请求
主机 = 'brd.superproxy.io'(brd.superproxy.io
port = 33335
username = 'brd-customer--zone-'
password = ''
proxy_url = f'http://{用户名}:密码@{主机}:端口'
proxies = {
http: proxy_url、
https: proxy_url
}
url = "https://www.example.com/homes/for_sale/San-Francisco/"
response = requests.get(url, proxies=proxies)
请注意: 对于本地代理访问,请安装 Bright Data SSL 证书以避免 SSL 错误,或设置
verify=False的请求(不建议用于生产)。
处理 JavaScript 渲染的内容
如果页面返回的数据不完整,请使用 x-unblock-expect 标头,以等待特定元素:
headers = {
"Authorization": f"承载器 {API_KEY}",
"内容类型": "application/json"
}
有效载荷 = {
"区":ZONE_NAME、
"url": "https://www.example.com/property/12345",
"格式": "原始",
"headers": {
"x-unblock-expect": '{"元素": ".属性详情"}'
}
}
选项 2:浏览器 API(用于交互式页面)
当您需要完整的浏览器交互(点击按钮、滚动、处理登录流)时,请使用浏览器 API。有关其他工具,请阅读 我的文章:最好的搜索浏览器.
最适合
- 需要交互的 JavaScript 密集型网站
- 多步骤导航流程
- 具有复杂反僵尸检测功能的网站
Puppeteer示例
const puppeteer = require(puppeteer-core);
const AUTH = 您的用户名:您的密码;
const TARGET_URL = 'https://www.example.com/homes/for_sale/San-Francisco/';
async function scrapeRealEstate() {
const browserWSEndpoint = `wss://${@brd.superproxy.io">AUTH}@brd.superproxy.io:9222`;
const browser = await puppeteer.connect({ browserWSEndpoint });
try {
const page = await browser.newPage();
await page.goto(TARGET_URL, { timeout: 120000 });
// 等待加载列表
await page.waitForSelector('[data-testid=")财产-卡片"]');
// 提取数据
const listings = await page.evaluate(() => {
const cards = document.querySelectorAll('[data-testid=")财产-卡片"]');
return Array.from(cards).map(card => ({
地址:card.querySelector('address')?.textContent?.trim()、
价格:card.querySelector('[data-test="财产-卡价"]')?.textContent?.trim()、
link: card.querySelector('a')?.href
}));
});
console.log(listings);
} finally {
await browser.close();
}
}
scrapeRealEstate();
剧作家范例
from playwright.sync_api import 同步播放器
认证 = 您的用户名:您的密码
def 搜索房地产():
with sync_playwright() as p:
browser = p.chromium.connect_over_cdp(f'wss://{@brd.superproxy.io">AUTH}@brd.superproxy.io:9222')
page = browser.new_page()
page.goto('https://www.example.com/homes/for_sale/San-Francisco/', timeout=120000)
page.wait_for_selector('[data-testid=")财产-卡"]' )
listings = page.evaluate('''() => {
const cards = document.querySelectorAll('[data-testid=")财产-card"]');
return Array.from(cards).map(card => ({
地址:card.querySelector('address')?.textContent?.trim()、
价格:card.querySelector('[data-test="财产-card-price"]')?.textContent?.trim()、
link: card.querySelector('a')?.href
}));
}''')
browser.close()
返回列表
选项 3:网络抓取程序 API(预构建的抓取程序)
对于像 Zillow 这样的热门房地产网站、 房地产经纪人网,或 Redfin、Bright Data 和 其他供应商 提供直接返回结构化数据的预建刮擦工具。
import 请求
API_KEY = "YOUR_API_KEY"
DATASET_ID = "gd_xxxxx" # 房地产刮板 ID
headers = {
"Authorization": f "承载器 {API_KEY}",
"内容类型": "application/json"
}
# 同步扫描(最多 20 个 URL)
response = requests.post(
f "https://api.brightdata.com/datasets/v3/scrape?dataset_id={DATASET_ID}&format=json",
headers=headers、
json=[{"url": "https://www.zillow.com/homedetails/123-main-st/12345_zpid/"}]
)
data = response.json()
分页和多页
房地产列表跨越多个页面。通过迭代页码来处理分页:
import requests
from bs4 import BeautifulSoup
import 时间
API_KEY = "YOUR_API_KEY"
ZONE_NAME = "您的区域名称"
BASE_URL = "https://www.example.com/homes/for_sale/San-Francisco/"
all_results = []
for 页码 in range(1, 6):
url = f"{BASE_URL}?page={page_num}"
有效载荷 = {
"区":ZONE_NAME、
"url": url、
"格式": "原始"
}
response = requests.post(
"https://api.brightdata.com/request",
headers={"Authorization": f "承载器 {API_KEY}", "内容类型": "application/json"},
json=payload
)
if response.status_code == 200:
soup = BeautifulSoup(response.text、 html.parser)
# 解析和附加结果
# ...
time.sleep(1) # 基本速率限制
提取完整的属性详细信息
列表页面包含的数据有限。请抓取单个房产页面以获取完整信息:
def 刮取属性细节(property_url, api_key, zone_name):
有效载荷 = {
"区"区域名称、
"url": property_url、
"格式": "原始"
}
response = requests.post(
"https://api.brightdata.com/request",
headers={"Authorization": f "承载器 {api_key}", "内容类型": "application/json"},
json=payload
)
if response.status_code == 200:
soup = BeautifulSoup(response.text、 html.parser)
return {
"描述": soup.find("div", {"data-testid": "描述"})?.get_text(strip=True),
"卧室": soup.find("span", {"data-testid": "床铺"})?.get_text(strip=True),
"浴室": soup.find("span", {"data-testid": "浴缸"})?.get_text(strip=True),
"平方英尺": soup.find("span", {"data-testid": "平方英尺"})?.get_text(strip=True),
}
return None
# 丰富列表数据
for 目录 in 结果:
details = scrape_property_details(listing["link"],api_key,zone_name)
if 详细信息
listing.update(details)
选择正确的产品

摘要
- 从简单开始 使用 requests 和 BeautifulSoup 处理基础网站
- 使用解锁程序 API 在静态页面上遇到反僵尸保护时
- 切换到浏览器 API 当页面需要 JavaScript 交互时
- 可以考虑使用 Web Scraper API 为热门网站提供预置搜索器
- 处理分页 在多个页面上收集数据
- 抓取详细页面 获取完整的物业信息

