如何抓取房地产数据:完整指南

从网站上抓取房地产数据是一项独特的挑战。房地产网站使用 JavaScript 渲染、动态内容加载和反僵尸措施来阻止传统的抓取工具。本指南涵盖实用的解决方案,使用 Python 和 Bright Data公司的工具.

请注意: 我与 Bright Data 没有任何关系。这是我最熟悉的平台,因此我选择在这里使用它。

为什么房地产搜索具有挑战性?

房地产网站存在三大障碍:

1.摘要页与详细页
搜索结果显示的数据有限(价格、地址、缩略图)。完整的房产详细信息--平方英尺、房产历史、代理信息--需要访问单个列表页面,这就成倍增加了所需请求的数量。

2.JavaScript 渲染
大多数房地产平台在客户端呈现内容。基本 HTTP 请求会返回不完整的 HTML,因为数据是在初始页面加载后通过 JavaScript 加载的。

3.反僵尸保护
网站采用 IP 过滤、验证码、速率限制和浏览器指纹识别来检测和阻止刮擦程序。

带请求和 BeautifulSoup 的基本爬虫

这种方法适用于没有大量反僵尸措施的简单网站。

检查目标页面

在编写代码之前,请检查页面结构:

  1. 在浏览器中打开搜索结果
  2. 右键单击物业列表,选择 "检查
  3. 确定包含所需数据(价格、地址、链接)的 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)

选择正确的产品

摘要

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

类似文章