2026-02-16 18:00:48 +01:00
2026-02-16 18:00:48 +01:00
2026-02-15 10:04:41 +01:00
2026-02-15 10:04:41 +01:00
2026-02-15 10:04:41 +01:00
2026-02-15 10:04:41 +01:00
2026-02-15 12:06:06 +01:00
2026-02-15 12:32:07 +01:00
2026-02-15 10:04:41 +01:00
2026-02-15 10:04:41 +01:00
2026-02-15 10:04:41 +01:00

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

  1. Neue Scraper-Klasse in src/scrapers/:
from .base_scraper import BaseScraper

class NewSiteScraper(BaseScraper):
    async def scrape(self, search_params):
        # Implementierung
        pass
  1. 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-sandbox fü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/data für persistente CSVs
  • Environment Support: --env-file .env für sensitive Daten
  • Scheduler Service: Automatische Ausführung alle 6 Stunden
  • Restart Policy: unless-stopped für Zuverlässigkeit

Troubleshooting

Häufige Probleme

  1. Browser startet nicht: playwright install-deps chromium
  2. Keine Ergebnisse: PLZ nicht verfügbar oder Website geändert
  3. Email funktioniert nicht: SMTP-Einstellungen und Security prüfen
  4. Environment nicht geladen: .env Datei prüfen und Rechte
  5. Docker Socket Fehler: Podman vs Docker Konflikt
  6. TypeError: int() argument must be a string: Environment Variable fehlt oder hat Default-Wert nicht
  7. 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 in sites.yaml angepasst werden)
  • Format: Zeitstempel - Modul - Level - Nachricht
  • Output: Console + Docker Logs

Sicherheit

Environment Variables

  • .env wird nicht in Git eingecheckt (siehe .gitignore)
  • .env.example als 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üsselung
  • ssl - 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
No description provided
Readme 211 KiB
Languages
Python 72%
Shell 25.4%
Dockerfile 2.6%