Як зібрати дані про нерухомість: повний гайд

Вебскрапінг даних про нерухомість із вебсайтів створює унікальні виклики. Сайти з оголошеннями про нерухомість використовують рендеринг JavaScript, динамічне підвантаження контенту та антибот-захист, який блокує традиційні вебскрапери. Цей посібник описує практичні рішення із застосуванням Python and Інструменти Bright Data.

'axios' Я не пов’язаний із Bright Data. Це платформа, з якою я найкраще знайомий, тому обрав її для цього прикладу.

Чому вебскрапінг даних про нерухомість є складним

Сайти нерухомості створюють три основні перешкоди:

1. Сторінки-списки vs. детальні сторінки
Результати пошуку показують лише обмежений набір даних (ціна, адреса, мініатюра). Повні відомості про об’єкт — квадратура, історія об’єкта, дані про агента — потребують переходу на окремі сторінки оголошень, що кратно збільшує кількість необхідних запитів.

2. JavaScript Rendering
Більшість сайтів нерухомості рендерять контент на боці клієнта. Простий HTTP-запит повертає неповний HTML, бо дані завантажуються через JavaScript після первинного завантаження сторінки.

3. Anti-Bot Protection
Сайти впроваджують IP-фільтрацію, CAPTCHA, обмеження частоти запитів і виявлення за браузерним відбитком, щоб виявляти та блокувати вебскраперів.

Базовий вебскрапер на Requests і BeautifulSoup

Цей підхід працює для простих сайтів без складних антибот-механізмів.

Аналіз цільової сторінки

Перед написанням коду вивчіть структуру сторінки:

  1. Відкрийте результати пошуку у браузері
  2. Клацніть правою кнопкою миші на оголошенні про нерухомість і виберіть «Перевірити»
  3. Визначте HTML-елементи, що містять потрібні вам дані (ціна, адреса, посилання)

Installation

pip install requests beautifulsoup4

Basic Scraper Code

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(response.content, 'html.parser')
    results = []
    property_items = soup.find_all("li", {"data-testid": "property-card"})
    for item in property_items:
        try:
            address = item.find("address").get_text(strip=True)
            price = item.find("span", {"data-test": "property-card-price"}).get_text(strip=True)
            url_link = item.find("a").get("href")
            full_url = f"https://www.example.com{url_link}" if url_link and not url_link.startswith("http") else url_link
            if address or price:
                results.append({
                    "address": адреса,
                    "price": price,
                    "link": full_url
                })
        except Exception as e:
            print(f"Error parsing card: {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)} listings")
else:
    print(f"Failed to fetch page. Status code: {response.status_code}")

Limitation: Цей підхід не працює на сайтах із рендерингом JavaScript або антибот-захистом.

Робота з антибот-захистом за допомогою Bright Data

Коли базовий вебскрапінг не дає результатів, Bright Data пропонує кілька рішень залежно від ваших потреб.

Варіант 1: Unlocker APIs (рекомендовано для статичних сторінок)

Unlocker API обробляють ротація проксіРозв’язання CAPTCHA, and anti-bot bypassing automatically. You send one request; it returns clean HTML or JSON.

Найкраще для:

  • Сторінки, які не потребують взаємодії з браузером
  • Масовий вебскрапінг із передбачуваними витратами
  • Команди без проксі-інфраструктури

Прямий доступ до API (рекомендований метод)

import requests
API_KEY = "YOUR_API_KEY"
ZONE_NAME = "YOUR_ZONE_NAME"
headers = {
    "Authorization": f"Bearer {API_KEY}",
    "Content-Type": "application/json"
}
payload = {
    "zone": ZONE_NAME,
    "url": "https://www.example.com/homes/for_sale/San-Francisco/",
    "format": "raw"
}
response = requests.post(
    "https://api.brightdata.com/request",
    headers=headers,
    json=payload
)
if response.status_code == 200:
    html_content = response.text
    # Parse with BeautifulSoup
    soup = BeautifulSoup(html_content, 'html.parser')
    # Extract data as shown above

Native Proxy-Based Access

Для робочих процесів, які вже використовують маршрутизацію через проксі:

import requests
host = 'brd.superproxy.io'
port = 33335
username = 'brd-customer--zone-'
password = ''
proxy_url = f'http://{username}:{password}@{host}:{port}'
proxies = {
    'http': proxy_url,
    'https': proxy_url
}
url = "https://www.example.com/homes/for_sale/San-Francisco/"
response = requests.get(url, proxies=proxies)

'axios' Для нативного доступу через проксі встановіть SSL-сертифікат Bright Data, щоб уникнути SSL-помилок, або задайте verify=False у ваших запитах (не рекомендовано для продакшну).

Handling JavaScript-Rendered Content

Якщо сторінки повертають неповні дані, використовуйте x-unblock-expect заголовок для очікування конкретних елементів:

headers = {
    "Authorization": f"Bearer {API_KEY}",
    "Content-Type": "application/json"
}
payload = {
    "zone": ZONE_NAME,
    "url": "https://www.example.com/property/12345",
    "format": "raw",
    "headers": {
        "x-unblock-expect": '{"element": ".property-details"}'
    }
}

Option 2: Browser API (For Interactive Pages)

When you need full browser interaction — clicking buttons, scrolling, handling login flows — use the Browser API. For other tools, read my article about the best scraping browsers.

Найкраще для:

  • JavaScript-heavy sites requiring interaction
  • Multi-step navigation flows
  • Sites with complex anti-bot detection

Puppeteer Example

const puppeteer = require('puppeteer-core');
const AUTH = 'YOUR_USERNAME:YOUR_PASSWORD';
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 });
        
        // Wait for listings to load
        await page.waitForSelector('[data-testid="property-card"]');
        
        // Extract data
        const listings = await page.evaluate(() => {
            const cards = document.querySelectorAll('[data-testid="property-card"]');
            return Array.from(cards).map(card => ({
                address: card.querySelector('address')?.textContent?.trim(),
                price: card.querySelector('[data-test="property-card-price"]')?.textContent?.trim(),
                link: card.querySelector('a')?.href
            }));
        });
        
        console.log(listings);
    } finally {
        await browser.close();
    }
}
scrapeRealEstate();

Playwright Example

from playwright.sync_api import sync_playwright
AUTH = 'YOUR_USERNAME:YOUR_PASSWORD'
def scrape_real_estate():
    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="property-card"]')
        
        listings = page.evaluate('''() => {
            const cards = document.querySelectorAll('[data-testid="property-card"]');
            return Array.from(cards).map(card => ({
                address: card.querySelector('address')?.textContent?.trim(),
                price: card.querySelector('[data-test="property-card-price"]')?.textContent?.trim(),
                link: card.querySelector('a')?.href
            }));
        }''')
        
        browser.close()
        return listings

Варіант 3: Web Scraper API (Готові вебскрапери)

Для популярних сайтів нерухомості, як-от Zillow, Realtor.com, або Redfin, Bright Data та інші провайдери пропонують готові вебскрапери, які одразу повертають структуровані дані.

import requests
API_KEY = "YOUR_API_KEY"
DATASET_ID = "gd_xxxxx"  # Real estate scraper ID
headers = {
    "Authorization": f"Bearer {API_KEY}",
    "Content-Type": "application/json"
}
# Synchronous scraping (up to 20 URLs)
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 time
API_KEY = "YOUR_API_KEY"
ZONE_NAME = "YOUR_ZONE_NAME"
BASE_URL = "https://www.example.com/homes/for_sale/San-Francisco/"
all_results = []
for page_num in range(1, 6):
    url = f"{BASE_URL}?page={page_num}"
    
    payload = {
        "zone": ZONE_NAME,
        "url": url,
        "format": "raw"
    }
    
    response = requests.post(
        "https://api.brightdata.com/request",
        headers={"Authorization": f"Bearer {API_KEY}", "Content-Type": "application/json"},
        json=payload
    )
    
    if response.status_code == 200:
        soup = BeautifulSoup(response.text, 'html.parser')
        # Parse and append results
        # ...
    
    time.sleep(1)  # Basic rate limiting

Витягнення повних даних про об’єкт нерухомості

Сторінки зі списком оголошень містять обмежений обсяг даних. Для повної інформації виконуйте вебскрапінг окремих сторінок об'єктів:

def scrape_property_details(property_url, api_key, zone_name):
    payload = {
        "zone": zone_name,
        "url": property_url,
        "format": "raw"
    }
    
    response = requests.post(
        "https://api.brightdata.com/request",
        headers={"Authorization": f"Bearer {api_key}", "Content-Type": "application/json"},
        json=payload
    )
    
    if response.status_code == 200:
        soup = BeautifulSoup(response.text, 'html.parser')
        return {
            "description": soup.find("div", {"data-testid": "description"})?.get_text(strip=True),
            "bedrooms": soup.find("span", {"data-testid": "beds"})?.get_text(strip=True),
            "bathrooms": soup.find("span", {"data-testid": "baths"})?.get_text(strip=True),
            "sqft": soup.find("span", {"data-testid": "sqft"})?.get_text(strip=True),
        }
    return None
# Enrich listing data
for listing in results:
    details = scrape_property_details(listing["link"], API_KEY, ZONE_NAME)
    if details:
        listing.update(details)

Вибір відповідного продукту

Summary

  1. Почніть із простого за допомогою requests і BeautifulSoup для простих сайтів
  2. Use Unlocker API коли ви стикаєтеся з антибот-захистом на статичних сторінках
  3. Перейдіть на Browser API коли сторінки потребують взаємодії за допомогою JavaScript
  4. Розгляньте Web Scraper API для популярних сайтів із готовими вебскраперами
  5. Обробка пагінації щоб збирати дані з кількох сторінок
  6. Вебскрапінг сторінок із детальною інформацією для повної інформації про об’єкт нерухомості

Схожі записи