Python Tool: IP-Adresse mit Geolocation Land, Stadt, Provider, Koordinaten.

Mit diesem Python-Skript kannst du dir deine IP-Adresse einschließlich Geolocation-Details (Land, Stadt, Provider, Koordinaten usw.) anzeigen. Dafür nutze ich eine kostenlose Web-API (ip-api.com), da echte Geolocation-Daten nicht lokal auf dem Rechner liegen, sondern von einem Online-Dienst abgefragt werden müssen.




#!/usr/bin/env python3
# *****************************************************************************
# Grafische Oberfläche (PyQt6) zur Anzeige von Details und geografischem 
# Standort (Geolocation) einer IP-Adresse. Nutzt den kostenlosen Dienst 
# ip-api.com (keine Anmeldung nötig, für private/nicht-kommerzielle Nutzung, 
# Limit: 45 Anfragen/Minute).
# Installation der Abhängigkeit: pip install PyQt6 requests
# Start: python ip_geolocation_gui.py         (c) Hans Busche Datum: 10.07.2026
# *****************************************************************************

import sys
import re
import requests

from PyQt6.QtCore import Qt, QThread, pyqtSignal
from PyQt6.QtWidgets import (
    QApplication,
    QMainWindow,
    QWidget,
    QVBoxLayout,
    QHBoxLayout,
    QFormLayout,
    QLabel,
    QLineEdit,
    QPushButton,
    QTextEdit,
    QMessageBox,
    QGroupBox,
)

API_URL = "http://ip-api.com/json/{ip}?fields=status,message,query,continent,\
country,countryCode,region,regionName,city,zip,lat,lon,timezone,\
isp,org,as,mobile,proxy,hosting"

# *****************************************************************************
# Hilfsfunktion: einfache Prüfung, ob Text wie eine IPv4/IPv6-Adresse aussieht
# (grobe Prüfung -- die eigentliche Validierung übernimmt die API selbst)
# *****************************************************************************
def sieht_aus_wie_ip_oder_domain(text: str) -> bool:
    text = text.strip()
    if not text:
        return False
    # Sehr grobe Prüfung: erlaubt IPv4, IPv6, Domainnamen
    muster = r"^[a-zA-Z0-9\.\:\-]+$"
    return bool(re.match(muster, text))

# *****************************************************************************
# Worker-Thread für die Netzwerkabfrage (damit die GUI nicht einfriert)
# *****************************************************************************
class AbfrageWorker(QThread):
    ergebnis = pyqtSignal(dict)
    fehler = pyqtSignal(str)
    def __init__(self, ziel: str):
        super().__init__()
        self.ziel = ziel.strip()
    def run(self):
        try:
            url = API_URL.format(ip=self.ziel)
            antwort = requests.get(url, timeout=8)
            antwort.raise_for_status()
            daten = antwort.json()
            if daten.get("status") != "success":
                meldung = daten.get("message", "Unbekannter Fehler")
                self.fehler.emit(f"Abfrage fehlgeschlagen: {meldung}")
                return
            self.ergebnis.emit(daten)
        except requests.exceptions.Timeout:
            self.fehler.emit("Zeitüberschreitung: Der Dienst hat nicht rechtzeitig geantwortet.")
        except requests.exceptions.ConnectionError:
            self.fehler.emit("Keine Verbindung möglich. Bitte Internetverbindung prüfen.")
        except requests.exceptions.RequestException as e:
            self.fehler.emit(f"Netzwerkfehler: {e}")
        except Exception as e:
            self.fehler.emit(f"Unerwarteter Fehler: {e}")

# *****************************************************************************
# Hauptfenster
# *****************************************************************************
class HauptFenster(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("IP-Adresse & Geolocation")
        self.setMinimumWidth(560)
        self.worker = None
        zentral = QWidget()
        self.setCentralWidget(zentral)
        haupt_layout = QVBoxLayout(zentral)
        # --- Eingabezeile ---
        eingabe_layout = QHBoxLayout()
        eingabe_layout.addWidget(QLabel("IP-Adresse / Domain:"))
        self.eingabe_feld = QLineEdit()
        self.eingabe_feld.setPlaceholderText("z. B. 8.8.8.8 oder example.com")
        self.eingabe_feld.returnPressed.connect(self.abfragen)
        eingabe_layout.addWidget(self.eingabe_feld)
        eigene_ip_btn = QPushButton("Eigene IP")
        eigene_ip_btn.setToolTip("Feld leer lassen und abfragen = eigene öffentliche IP")
        eigene_ip_btn.clicked.connect(self.eigene_ip_verwenden)
        eingabe_layout.addWidget(eigene_ip_btn)
        eigene_ip_btn.setStyleSheet(
            """
            QPushButton {
                background-color: #dbc7a2;
                color: black;
                font-size: 12px;
                font-weight: bold;
                border-radius: 6px;
                padding: 8px 16px;
            }
            """
        )
        haupt_layout.addLayout(eingabe_layout)
        # --- Abfrage-Button (markant gestaltet) ---
        self.abfragen_btn = QPushButton("Details abfragen")
        self.abfragen_btn.clicked.connect(self.abfragen)
        self.abfragen_btn.setCursor(Qt.CursorShape.PointingHandCursor)
        self.abfragen_btn.setMinimumHeight(45)
        self.abfragen_btn.setStyleSheet(
            """
            QPushButton {
                background-color: #1565c0;
                color: white;
                font-size: 15px;
                font-weight: bold;
                border-radius: 6px;
                padding: 8px 16px;
            }
            """
        )
        haupt_layout.addWidget(self.abfragen_btn)
        # --- Ergebnis-Gruppe ---
        ergebnis_box = QGroupBox("Details")
        formular = QFormLayout()
        self.feld_ip = QLabel("–")
        self.feld_land = QLabel("–")
        self.feld_region = QLabel("–")
        self.feld_stadt = QLabel("–")
        self.feld_plz = QLabel("–")
        self.feld_koordinaten = QLabel("–")
        self.feld_zeitzone = QLabel("–")
        self.feld_isp = QLabel("–")
        self.feld_organisation = QLabel("–")
        self.feld_as = QLabel("–")
        self.feld_hinweise = QLabel("–")
        formular.addRow("IP-Adresse:", self.feld_ip)
        formular.addRow("Land:", self.feld_land)
        formular.addRow("Region/Bundesland:", self.feld_region)
        formular.addRow("Stadt:", self.feld_stadt)
        formular.addRow("Postleitzahl:", self.feld_plz)
        formular.addRow("Koordinaten:", self.feld_koordinaten)
        formular.addRow("Zeitzone:", self.feld_zeitzone)
        formular.addRow("Internetanbieter (ISP):", self.feld_isp)
        formular.addRow("Organisation:", self.feld_organisation)
        formular.addRow("AS-Nummer:", self.feld_as)
        formular.addRow("Hinweise:", self.feld_hinweise)
        ergebnis_box.setLayout(formular)
        haupt_layout.addWidget(ergebnis_box)
        # --- Kartenlink ---
        self.karten_link = QLabel()
        self.karten_link.setOpenExternalLinks(True)
        self.karten_link.setText("")
        haupt_layout.addWidget(self.karten_link)
        # --- Rohdaten / Protokoll ---
        haupt_layout.addWidget(QLabel("Protokoll / Rohdaten:"))
        self.log_ausgabe = QTextEdit()
        self.log_ausgabe.setReadOnly(True)
        haupt_layout.addWidget(self.log_ausgabe)
    def eigene_ip_verwenden(self):
        self.eingabe_feld.clear()
        self.abfragen()
    def abfragen(self):
        ziel = self.eingabe_feld.text().strip()
        # Leeres Feld ist erlaubt -> ip-api.com liefert dann die eigene öffentliche IP
        if ziel and not sieht_aus_wie_ip_oder_domain(ziel):
            QMessageBox.warning(
                self, "Ungültige Eingabe",
                "Bitte eine gültige IP-Adresse oder Domain eingeben."
            )
            return
        self.abfragen_btn.setEnabled(False)
        self.log_ausgabe.append(f"Frage Details an für: {ziel if ziel else '(eigene öffentliche IP)'} …")
        self.worker = AbfrageWorker(ziel)
        self.worker.ergebnis.connect(self.zeige_ergebnis)
        self.worker.fehler.connect(self.zeige_fehler)
        self.worker.finished.connect(lambda: self.abfragen_btn.setEnabled(True))
        self.worker.start()
    def zeige_ergebnis(self, daten: dict):
        self.feld_ip.setText(daten.get("query", "–"))
        land = daten.get("country", "–")
        code = daten.get("countryCode", "")
        self.feld_land.setText(f"{land} ({code})" if code else land)
        self.feld_region.setText(daten.get("regionName", "–") or "–")
        self.feld_stadt.setText(daten.get("city", "–") or "–")
        self.feld_plz.setText(daten.get("zip", "–") or "–")
        lat = daten.get("lat")
        lon = daten.get("lon")
        if lat is not None and lon is not None:
            self.feld_koordinaten.setText(f"{lat}, {lon}")
            self.karten_link.setText(
                f'Auf Google Maps anzeigen'
            )
        else:
            self.feld_koordinaten.setText("–")
            self.karten_link.setText("")
        self.feld_zeitzone.setText(daten.get("timezone", "–") or "–")
        self.feld_isp.setText(daten.get("isp", "–") or "–")
        self.feld_organisation.setText(daten.get("org", "–") or "–")
        self.feld_as.setText(daten.get("as", "–") or "–")
        hinweise = []
        if daten.get("mobile"):
            hinweise.append("Mobilfunknetz")
        if daten.get("proxy"):
            hinweise.append("Proxy/VPN erkannt")
        if daten.get("hosting"):
            hinweise.append("Hosting-/Rechenzentrums-IP")
        self.feld_hinweise.setText(", ".join(hinweise) if hinweise else "keine besonderen Merkmale")
        self.log_ausgabe.append(f"Erfolgreich abgefragt: {daten.get('query', '')}")
        self.log_ausgabe.append(str(daten))
        self.log_ausgabe.append("")
    def zeige_fehler(self, meldung: str):
        self.log_ausgabe.append(f"FEHLER: {meldung}")
        QMessageBox.warning(self, "Fehler bei der Abfrage", meldung)

# *****************************************************************************
# Main
# *****************************************************************************
def main():
    app = QApplication(sys.argv)
    fenster = HauptFenster()
    fenster.show()
    sys.exit(app.exec())

if __name__ == "__main__":
    main()
# *****************************************************************************
# Ende
# *****************************************************************************


        
🐍 Skript herunterladen (.py)