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)