Flat Scraper
Automatischer Web Scraper für Wohnungangebote auf NHG.at mit Benachrichtigungen bei neuen Ergebnissen.
Features
- 🏠 Automatisches Scraping von NHG.at Wohnungsangeboten
- 📍 PLZ-basierte Suche für 1120, 1140, 1150, 1160
- 📊 CSV Storage für Ergebnisverfolgung
- 🔔 Benachrichtigungen bei neuen Wohnungen (Console + Email)
- 🐳 Docker Support für Raspberry Pi (ARM64)
- ⏰ Automatisierte Ausführung alle 6 Stunden
- 🔐 Environment Variables für sensitive Daten (.env)
- 📧 Email Security (SSL/TLS/STARTTLS Support)
Projektstruktur
flat_scraper/
├── src/
│ ├── scrapers/ # Scraper Module
│ │ ├── base_scraper.py # Basis-Klasse
│ │ └── nhg_scraper.py # NHG.at spezifisch
│ ├── storage/ # Daten-Speicher
│ │ └── csv_storage.py # CSV-basiert
│ ├── notifier/ # Benachrichtigungen
│ │ └── email_notifier.py
│ ├── config/ # Konfiguration
│ │ └── sites.yaml
│ ├── config_loader.py # Konfigurations-Loader mit .env Support
│ └── main.py # Hauptanwendung
├── data/ # CSV Ergebnisse
├── .env.example # Environment Vorlage
├── .env # Deine sensitiven Daten (nicht in VCS)
├── .gitignore # Git ignore für .env und data/
├── requirements.txt # Python Dependencies
├── Dockerfile # ARM64 optimiert
├── deploy.sh # Automatisches Deployment Script
├── docker-compose.yml # Automatisierung
└── README.md
Quick Start
1. Environment einrichten
# Environment Vorlage kopieren
cp .env.example .env
# Deine Daten eintragen
vim .env
Wichtige .env Variablen:
SMTP_SERVER=smtp.gmail.com
SMTP_PORT=587
EMAIL_USERNAME=deine-email@gmail.com
EMAIL_PASSWORD=dein-app-password
EMAIL_FROM=deine-email@gmail.com
EMAIL_TO=empfänger@example.com
EMAIL_SECURITY=starttls # Options: none, ssl, tls, starttls
2. Docker auf Raspberry Pi
# Build und Start
docker-compose up -d
# Logs ansehen
docker-compose logs -f flat-scraper
# Scheduler starten (automatisch alle 6 Stunden)
docker-compose up -d scheduler
3. Manuelles Testen
# Einmaliger Lauf
docker-compose run --rm flat-scraper
# Mit Environment File
docker run --rm -v $(pwd):/app --env-file .env flat-scraper-test python src/main.py
Konfiguration
Sites konfigurieren (src/config/sites.yaml)
sites:
nhg:
name: "Neue Heimat Gewog"
url: "https://nhg.at/immobilienangebot/wohnungsangebot/"
scraper_class: "nhg_scraper.NHGScraper"
enabled: true
search_params:
plz_list:
- "1120 Wien"
- "1140 Wien"
- "1150 Wien"
- "1160 Wien"
schedule:
cron: "0 */6 * * *" # Alle 6 Stunden
timezone: "Europe/Vienna"
Email-Benachrichtigungen
notification:
email:
enabled: true
smtp_server: "${SMTP_SERVER}"
smtp_port: "${SMTP_PORT}"
username: "${EMAIL_USERNAME}"
password: "${EMAIL_PASSWORD}"
from_email: "${EMAIL_FROM}"
to_emails:
- "${EMAIL_TO}"
security: "${EMAIL_SECURITY:starttls}" # Options: none, ssl, tls, starttls
console:
enabled: true # Immer für Debugging
Datenformat
Ergebnisse werden als CSV gespeichert:
scrape_time,plz,address,link,hash,scraper
2024-01-15T10:30:00,1120,"1120 Wien, Flurschützstraße 5 / 2 / 10",https://...,abc123,nhg
Hash-basierter Vergleich vermeidet Duplikate zwischen Läufen.
Erweiterbarkeit
Neue Webseite hinzufügen
- Neue Scraper-Klasse in
src/scrapers/:
from .base_scraper import BaseScraper
class NewSiteScraper(BaseScraper):
async def scrape(self, search_params):
# Implementierung
pass
- Konfiguration erweitern:
sites:
new_site:
name: "New Site"
url: "https://example.com"
scraper_class: "new_site_scraper.NewSiteScraper"
enabled: true
search_params:
# Site-spezifische Parameter
Environment Variables
Der ConfigLoader unterstützt automatische Substitution:
# In YAML
smtp_server: "${SMTP_SERVER}"
username: "${EMAIL_USERNAME:default@example.com}" # Mit Default
Deployment auf Raspberry Pi
Schritt-für-Schritt Anleitung
Voraussetzungen
- Raspberry Pi 4+ (empfohlen)
- Docker & Docker Compose installiert
- Git für das Klonen des Repositories
1. Repository auf Raspberry Pi laden
# Projekt klonen
git clone <dein-repo-url> flat_scraper
cd flat_scraper
# Oder manuell kopieren
scp -r ./flat_scraper pi@raspberry-pi:~/
2. Environment konfigurieren
# Environment Vorlage kopieren
cp .env.example .env
# Mit Editor öffnen
nano .env
# Oder vim .env
Deine SMTP-Daten eintragen:
SMTP_SERVER=dein-smtp-server.com
SMTP_PORT=587
EMAIL_USERNAME=deine-email@domain.com
EMAIL_PASSWORD=dein-app-password
EMAIL_FROM=deine-email@domain.com
EMAIL_TO=empfänger@domain.com
EMAIL_SECURITY=starttls
3. Docker Image bauen
# Image für ARM64 bauen (kann einige Minuten dauern)
docker build -t flat-scraper .
# Build-Status prüfen
docker images | grep flat-scraper
Fehlerbehandlung:
# Falls Docker Daemon nicht läuft:
sudo systemctl start docker
sudo systemctl enable docker
# Falls Podman-Socket Fehler:
# Prüfen ob Docker oder Podman aktiv ist:
which docker
which podman
# Docker Socket prüfen:
ls -la /var/run/docker.sock
sudo chmod 666 /var/run/docker.sock
# Falls nötig, Docker neu starten:
sudo systemctl restart docker
# Environment Variablen Fehler:
# Prüfen ob .env Datei existiert und korrekt ist:
ls -la .env
cat .env
# Falls SMTP_PORT nicht gesetzt ist:
echo "SMTP_PORT=587" >> .env
# Permission Fehler mit data/ Verzeichnis:
sudo chown -R $USER:$USER data/
chmod 755 data/
4. Erster Testlauf
# Einmaligen Scraper-Lauf testen
docker run --rm \
--env-file $(pwd)/.env \
-v $(pwd)/data:/app/data \
-v $(pwd)/src/config:/app/src/config \
flat-scraper python src/main.py
Erwartete Ausgabe:
2026-02-15 10:30:00 - INFO - Starting flat scraper run
2026-02-15 10:30:00 - INFO - Start scraping nhg
Scraping PLZ 1120 Wien...
Scraping PLZ 1140 Wien...
Scraping PLZ 1150 Wien...
Scraping PLZ 1160 Wien...
2026-02-15 10:30:15 - INFO - Found X results for nhg
Email-Benachrichtigung gesendet an 1 Empfänger
2026-02-15 10:30:15 - INFO - Scraping completed: 1/1 sites successful
5. Docker Compose konfigurieren
# ARM64 Support aktivieren (wichtig für Raspberry Pi)
sed -i 's/# platform: linux/arm64/platform: linux/arm64/' docker-compose.yml
# Konfiguration prüfen
cat docker-compose.yml
6. Production Deployment
# Manuelles Deployment
docker-compose up -d
# Status prüfen
docker-compose ps
# ODER: Automatisches Deployment Script verwenden
./deploy.sh
Deployment Script Features:
- ✅ Automatisches Build mit Fehlerprüfung
- ✅ Image Cleanup für Speicherplatz
- ✅ Status Überwachung vor/nach Deployment
- ✅ Flexible Optionen für verschiedene Szenarien
# Vollständiges Deployment mit Cleanup
./deploy.sh
# Deployment ohne Cleanup (für schnelle Tests)
./deploy.sh --no-cleanup
# Nur Services neu starten (kein Build)
./deploy.sh --no-build
# Verbose Output für Debugging
./deploy.sh --verbose
# Hilfe anzeigen
./deploy.sh --help
Erwartete Ausgabe:
NAME COMMAND SERVICE STATUS PORTS
flat_scraper-flat-scraper-1 "python src/main.py" flat-scraper running
flat_scraper-scheduler-1 "python -c 'import..." scheduler running
7. Logs überwachen
# Live Logs ansehen
docker-compose logs -f
# Nur Scraper Logs
docker-compose logs -f flat-scraper
# Nur Scheduler Logs
docker-compose logs -f scheduler
8. Automatisierung verifizieren
# Prüfen ob Scheduler läuft
docker-compose logs scheduler | grep "Scheduler started"
# Nächsten Lauf prüfen (alle 6 Stunden)
docker-compose logs scheduler | tail -10
9. Daten persistenz prüfen
# CSV Dateien prüfen
ls -la data/
# Inhalt ansehen
cat data/nhg_results.csv
# Letzte Ergebnisse
tail -5 data/nhg_results.csv
10. Wartung und Updates
# Services stoppen
docker-compose down
# Code aktualisieren
git pull origin main
# Automatisches Deployment mit Script
./deploy.sh
# ODER manueller Weg:
# Neues Image bauen
docker build -t flat-scraper .
# Services neu starten
docker-compose up -d
# Alte Images aufräumen
docker image prune -f
Deployment Script für Updates:
# Vollständiges Update mit Cleanup
./deploy.sh
# Schneller Restart ohne Build
./deploy.sh --no-build --no-cleanup
ARM64 Support
Der Dockerfile ist für ARM64 optimiert:
FROM python:3.11-slim-bullseye
# ARM64 optimierte Browser Installation
RUN apt-get update && apt-get install -y chromium
Performance-Tipps
--no-sandboxfür Chromium (im Dockerfile berücksichtigt)- Shared Browser Path:
PLAYWRIGHT_BROWSERS_PATH=/ms-playwright - Memory-optimierte Settings
- Environment Variables statt Hardcoding
Docker Compose Features
- Volume Mounting:
./data:/app/datafür persistente CSVs - Environment Support:
--env-file .envfür sensitive Daten - Scheduler Service: Automatische Ausführung alle 6 Stunden
- Restart Policy:
unless-stoppedfür Zuverlässigkeit
Troubleshooting
Häufige Probleme
- Browser startet nicht:
playwright install-deps chromium - Keine Ergebnisse: PLZ nicht verfügbar oder Website geändert
- Email funktioniert nicht: SMTP-Einstellungen und Security prüfen
- Environment nicht geladen:
.envDatei prüfen und Rechte - Docker Socket Fehler: Podman vs Docker Konflikt
- TypeError: int() argument must be a string: Environment Variable fehlt oder hat Default-Wert nicht
- Permission denied: data/nhg_results.csv: data/ Verzeichnis gehört falschem User
Docker/Podman Konflikt lösen
# 1. Prüfen welcher Container-Manager aktiv:
echo $CONTAINER_MANAGER
which docker
which podman
# 2. Docker als Standard setzen (falls nötig):
export DOCKER_HOST=unix:///var/run/docker.sock
# 3. Podman deaktivieren (falls gewünscht):
sudo systemctl disable podman
sudo systemctl stop podman
# 4. Docker Socket Rechte prüfen:
sudo ls -la /var/run/docker.sock
sudo usermod -aG docker $USER # User zur Docker Gruppe hinzufügen
newgrp docker # Gruppe neu laden
# 5. System neu starten nach Änderungen:
sudo systemctl restart docker
Raspberry Pi spezifische Probleme
# ARM64 Architektur prüfen:
uname -m
# Sollte: aarch64 oder armv7l
# Docker Architektur prüfen:
docker version --format '{{.Server.Arch}}'
# Falls x86_64 Images auf ARM64 laufen sollen:
# docker run --platform linux/arm64 flat-scraper
# Memory prüfen (mindestens 1GB empfohlen):
free -h
# Speicherplatz prüfen (mindestens 2GB frei):
df -h
Debugging
# Logs ansehen
docker-compose logs -f flat-scraper
# Manuell testen
docker-compose run --rm flat-scraper python src/main.py
# Email Test
docker run --rm -v $(pwd):/app --env-file .env flat-scraper-test python -c "
from src.notifier.email_notifier import EmailNotifier
from src.config_loader import ConfigLoader
config = ConfigLoader()
notifier = EmailNotifier(config.get_notification_config()['email'])
test_results = [{'plz': '1120', 'address': 'Test', 'link': '#', 'hash': 'test'}]
notifier.send_notification('test', test_results)
"
Entwicklung
Testing
# Einzelnen Scraper testen
python -c "
import asyncio
from src.scrapers.nhg_scraper import NHGScraper
scraper = NHGScraper({'url': 'https://nhg.at/immobilienangebot/wohnungsangebot/', 'search_params': {'plz_list': ['1120 Wien']}})
results = asyncio.run(scraper.scrape())
print(results)
"
Logging
Logs werden automatisch geschrieben:
- Level:
INFO(kann insites.yamlangepasst werden) - Format:
Zeitstempel - Modul - Level - Nachricht - Output: Console + Docker Logs
Sicherheit
Environment Variables
.envwird nicht in Git eingecheckt (siehe.gitignore).env.exampleals Vorlage für das Team- Keine Passwörter im Code oder in YAML
- Docker Secrets optional für Production
Email Security
Unterstützte Security Modi:
none- Keine Verschlüsselungssl- SMTP_SSL (Port 465)tls- Explicit TLS (Port 587 + STARTTLS)starttls- STARTTLS (Standard für Gmail)ssl/tls- Kompatibilitätsmodus
Architektur
Hybrid-Ansatz
- BaseScraper: Gemeinsame Funktionalität (Hashing, Metadata)
- Site-spezifische Scraper: Individuelle Implementierungen
- Config-Driven: YAML Konfiguration mit Environment Support
- Modular: Storage und Notifier austauschbar
Datenfluss
Config → Scraper → Results → Storage → Comparison → Notifier
↓ ↓ ↓ ↓ ↓
Environment Playwright CSV Hash-Vergleich Email/Console
Lizenz
MIT License
Description
Languages
Python
72%
Shell
25.4%
Dockerfile
2.6%