Scrape Bất Động Sản Với Python: Thu Thập Dữ Liệu Nhà Đất

Trở lại Tin tức
Tin tức

Scrape Bất Động Sản Với Python: Thu Thập Dữ Liệu Nhà Đất

Bất động sản là ngành có nhiều data cần scrape. Bài viết hướng dẫn scrape listings nhà đất từ các trang phổ biến.

Use Cases

  • Price analysis: Giá theo khu vực
  • Investment research: Tìm deals tốt
  • Market trends: Xu hướng giá
  • Agent tools: Database listings

Các Trang BĐS Việt Nam

  • batdongsan.com.vn
  • nha.chotot.com
  • homedy.com
  • muaban.net

Data Points Cần Thu Thập

  • Tiêu đề, mô tả
  • Giá (tổng, /m²)
  • Diện tích
  • Địa chỉ, quận/huyện
  • Số phòng ngủ/WC
  • Hướng nhà
  • Ngày đăng
  • Thông tin liên hệ

Scraper Code

import requests
from bs4 import BeautifulSoup
import re
import json

def scrape_listing(url):
    response = requests.get(url, headers={
        'User-Agent': 'Mozilla/5.0...'
    })
    soup = BeautifulSoup(response.text, 'lxml')
    
    # Extract data
    title = soup.select_one('h1.title').text.strip()
    
    # Price - handle various formats
    price_text = soup.select_one('.price').text
    price = parse_price(price_text)
    
    # Area
    area_text = soup.select_one('.area').text
    area = float(re.search(r'[\d.]+', area_text).group())
    
    # Location
    address = soup.select_one('.address').text.strip()
    district = extract_district(address)
    
    # Details
    details = {}
    for row in soup.select('.detail-row'):
        label = row.select_one('.label').text.strip()
        value = row.select_one('.value').text.strip()
        details[label] = value
    
    return {
        'title': title,
        'price': price,
        'price_per_m2': price / area if area else None,
        'area': area,
        'address': address,
        'district': district,
        'bedrooms': details.get('Phòng ngủ'),
        'bathrooms': details.get('Phòng tắm'),
        'url': url
    }

def parse_price(text):
    # "3.5 tỷ" -> 3500000000
    # "500 triệu" -> 500000000
    text = text.lower()
    number = float(re.search(r'[\d.]+', text).group())
    if 'tỷ' in text:
        return number * 1_000_000_000
    elif 'triệu' in text:
        return number * 1_000_000
    return number

Scrape Listings Page

def scrape_listings_page(url):
    response = requests.get(url, headers={'User-Agent': '...'})
    soup = BeautifulSoup(response.text, 'lxml')
    
    listings = []
    for item in soup.select('.listing-item'):
        listing_url = item.select_one('a')['href']
        listings.append(listing_url)
    
    return listings

# Scrape multiple pages
all_listings = []
for page in range(1, 11):
    url = f'https://batdongsan.com.vn/ban-nha?page={page}'
    listing_urls = scrape_listings_page(url)
    
    for listing_url in listing_urls:
        data = scrape_listing(listing_url)
        all_listings.append(data)
        time.sleep(2)  # Delay
    
    print(f"Page {page}: {len(listing_urls)} listings")

Analysis

import pandas as pd

df = pd.DataFrame(all_listings)

# Giá trung bình theo quận
avg_by_district = df.groupby('district')['price_per_m2'].mean()
print(avg_by_district.sort_values(ascending=False))

VinaProxy + Real Estate Scraping

  • IP Việt Nam cho local sites
  • Bypass anti-scraping
  • Giá chỉ $0.5/GB

Dùng Thử Ngay →