Suchen lokaler IP-Adressen mit Pythons stdlib


547

Wie kann ich lokale IP-Adressen (dh 192.168.xx oder 10.0.xx) in der Python-Plattform unabhängig und nur unter Verwendung der Standardbibliothek finden?


7
Die lokale IP? Oder öffentliche IP? Wie gehen Sie mit Systemen mit mehreren IPs um?
Sargun Dhillon

benutze ifconfig -aund benutze die Ausgabe von dort ...
Fredrik Pihl

16
@Fredrik Das ist eine schlechte Idee. Zunächst einmal müssen Sie unnötigerweise einen neuen Prozess forken, und dies kann dazu führen, dass Ihr Programm nicht in eng gesperrten Konfigurationen funktioniert (oder Sie müssen Rechte zulassen, die Ihr Programm nicht benötigt). Zweitens führen Sie Fehler für Benutzer verschiedener Ländereinstellungen ein. Drittens, wenn Sie sich entscheiden, überhaupt ein neues Programm zu starten, sollten Sie kein veraltetes Programm starten - dies ip addrist weitaus besser geeignet (und einfacher zu analysieren, zu booten).
Phihag

12
@phihag Sie sind absolut richtig, danke für die Korrektur meiner Dummheit
Fredrik Pihl

1
Ein grundlegenderes Problem besteht darin, dass in einem ordnungsgemäß geschriebenen modernen Netzwerkprogramm die richtige (Menge) lokaler IP-Adresse (n) vom Peer oder von der Menge potenzieller Peers abhängt. Wenn die lokale IP-Adresse für bindeinen Socket zu einer bestimmten Schnittstelle benötigt wird, ist dies eine Richtlinienangelegenheit. Wenn die lokale IP-Adresse benötigt wird, um sie an einen Peer zu übergeben, damit der Peer "zurückrufen" kann, dh um eine Verbindung zum lokalen Computer wiederherzustellen, hängt die Situation davon ab, ob NAT (Network Address Translation) vorhanden ist. Kisten dazwischen. Wenn es keine NATs gibt, getsocknameist dies eine gute Wahl.
Pekka Nikander

Antworten:


445
import socket
socket.gethostbyname(socket.gethostname())

Dies funktioniert nicht immer (kehrt 127.0.0.1auf Computern mit dem Hostnamen /etc/hostsas zurück 127.0.0.1). Ein Paliative wäre das, was Gimel zeigt. Verwenden Sie socket.getfqdn()stattdessen. Natürlich benötigt Ihr Computer einen auflösbaren Hostnamen.


43
Man sollte beachten, dass dies keine plattformunabhängige Lösung ist. Viele Linux-Benutzer geben mit dieser Methode 127.0.0.1 als IP-Adresse zurück.
Jason Baker

20
Eine Variation: socket.gethostbyname (socket.getfqdn ())
gimel

55
Dies scheint nur eine einzige IP-Adresse zurückzugeben. Was ist, wenn das Gerät mehrere Adressen hat?
Jason R. Coombs

26
Unter Ubuntu wird aus irgendeinem Grund 127.0.1.1 zurückgegeben.
Slikts

13
@ Jason R. Coombs, verwenden Sie folgenden Code, um eine Liste der IPv4-Adressen abzurufen, die zum Host-Computer gehören:socket.gethostbyname_ex(socket.gethostname())[-1]
Barmaley

460

Ich habe das gerade gefunden, aber es scheint ein bisschen hackisch zu sein, aber sie sagen, ich habe es auf * nix versucht und ich habe es unter Windows gemacht und es hat funktioniert.

import socket
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.connect(("8.8.8.8", 80))
print(s.getsockname()[0])
s.close()

Dies setzt voraus, dass Sie über einen Internetzugang verfügen und kein lokaler Proxy vorhanden ist.


31
Schön, wenn Sie mehrere Schnittstellen auf dem Computer haben und die benötigen, die an z. B. gmail.com weitergeleitet wird
elzapp

4
Es könnte eine gute Idee sein, socket.error-Ausnahmen abzufangen, die durch s.connect () ausgelöst werden können!
Phobie

39
Es ist besser, eine IP-Adresse anstelle eines Domainnamens zu verwenden - diese muss schneller und unabhängig von der DNS-Verfügbarkeit sein. Zum Beispiel können wir 8.8.8.8 IP verwenden - Googles öffentlichen DNS-Server.
Wobmene

10
Sehr clever, funktioniert perfekt. Anstelle von Google Mail oder 8.8.8.8 können Sie auch die IP-Adresse oder Adresse des Servers verwenden, von dem aus Sie gesehen werden möchten, sofern dies zutreffend ist.
Prof. Falken Vertrag verletzt

3
Dieses Beispiel hat eine externe Abhängigkeit davon, ob gmail.com tatsächlich aufgelöst werden kann. Wenn Sie eine IP-Adresse festlegen, die sich nicht in Ihrem lokalen LAN befindet (unabhängig davon, ob sie aktiv oder inaktiv ist), funktioniert sie ohne Abhängigkeiten und ohne Netzwerkverkehr.
grimmig

254

Diese Methode gibt die "primäre" IP auf der lokalen Box zurück (die mit einer Standardroute) .

  • Benötigt KEINEN routingfähigen Netzzugang oder irgendeine Verbindung.
  • Funktioniert auch, wenn alle Schnittstellen vom Netzwerk getrennt sind.
  • Benötigt oder versucht NICHT, irgendwo anders hinzukommen .
  • Funktioniert mit NAT, öffentlichen, privaten, externen und internen IPs
  • Reines Python 2 (oder 3) ohne externe Abhängigkeiten.
  • Funktioniert unter Linux, Windows und OSX.

Python 3 oder 2:

import socket
def get_ip():
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    try:
        # doesn't even have to be reachable
        s.connect(('10.255.255.255', 1))
        IP = s.getsockname()[0]
    except Exception:
        IP = '127.0.0.1'
    finally:
        s.close()
    return IP

Dies gibt eine einzelne IP zurück, die die primäre ist (die mit einer Standardroute). Wenn Sie stattdessen alle IP-Adressen benötigen, die an alle Schnittstellen (einschließlich localhost usw.) angeschlossen sind, lesen Sie diese Antwort .

Wenn Sie sich zu Hause hinter einer NAT-Firewall wie Ihrer WLAN-Box befinden, wird hier nicht Ihre öffentliche NAT-IP angezeigt, sondern Ihre private IP-Adresse im lokalen Netzwerk, das eine Standardroute zu Ihrem lokalen WLAN-Router hat. Um die externe IP-Adresse Ihres WLAN-Routers zu erhalten, müssen Sie diese entweder auf DIESER Box ausführen oder eine Verbindung zu einem externen Dienst wie whatismyip.com/whatismyipaddress.com herstellen, der die IP-Adresse wiedergeben könnte. Dies unterscheidet sich jedoch grundlegend von der ursprünglichen Frage. :) :)


7
Funktioniert in Raspbian mit Python 2 und 3!
pierce.jason

3
Brillant. Funktioniert unter Win7,8,8.1 + Linux Mint & Arch, einschließlich VMs.
Shermy

2
Funktioniert unter Windows 10 Pro! Vielen Dank, Jamieson Becker!
Varantes

3
Aus irgendeinem Grund funktioniert dies unter Mac OS X El Capitan 10.11.6 nicht (es wird ein Ausnahme-Betriebssystemfehler generiert: [Errno 49] Die angeforderte Adresse kann nicht zugewiesen werden). Das Ändern des Ports von '0' auf '1': s.connect (('10.255.255.255', 1)) funktionierte für mich sowohl unter Mac OS X als auch unter Linux Ubuntu 17.04
Pedro Scarapicchia Junior

10
Dies sollte die akzeptierte Antwort sein. socket.gethostbyname(socket.gethostname())gibt schreckliche Ergebnisse.
Jason Floyd

142

Wie ein Alias ​​heißt myip, sollte das überall funktionieren:

alias myip="python -c 'import socket; print([l for l in ([ip for ip in socket.gethostbyname_ex(socket.gethostname())[2] if not ip.startswith(\"127.\")][:1], [[(s.connect((\"8.8.8.8\", 53)), s.getsockname()[0], s.close()) for s in [socket.socket(socket.AF_INET, socket.SOCK_DGRAM)]][0][1]]) if l][0][0])'"
  • Funktioniert ordnungsgemäß mit Python 2.x, Python 3.x, modernen und alten Linux-Distributionen, OSX / macOS und Windows, um die aktuelle IPv4-Adresse zu ermitteln.
  • Gibt nicht das richtige Ergebnis für Computer mit mehreren IP-Adressen, IPv6, keiner konfigurierten IP-Adresse oder keinem Internetzugang zurück.

Wie oben, aber nur der Python-Code:

import socket
print([l for l in ([ip for ip in socket.gethostbyname_ex(socket.gethostname())[2] if not ip.startswith("127.")][:1], [[(s.connect(('8.8.8.8', 53)), s.getsockname()[0], s.close()) for s in [socket.socket(socket.AF_INET, socket.SOCK_DGRAM)]][0][1]]) if l][0][0])
  • Dies löst eine Ausnahme aus, wenn keine IP-Adresse konfiguriert ist.

Version, die auch in LANs ohne Internetverbindung funktioniert:

import socket
print((([ip for ip in socket.gethostbyname_ex(socket.gethostname())[2] if not ip.startswith("127.")] or [[(s.connect(("8.8.8.8", 53)), s.getsockname()[0], s.close()) for s in [socket.socket(socket.AF_INET, socket.SOCK_DGRAM)]][0][1]]) + ["no IP found"])[0])

(danke @ccpizza )


Hintergrund :

Die Verwendung socket.gethostbyname(socket.gethostname())hat hier nicht funktioniert, da einer der Computer, auf denen ich war, einen /etc/hostsmit doppelten Einträgen und Verweisen auf sich selbst hatte. socket.gethostbyname()Gibt nur den letzten Eintrag in zurück /etc/hosts.

Dies war mein erster Versuch, bei dem alle Adressen ausgesondert wurden, beginnend mit "127.":

import socket
print([ip for ip in socket.gethostbyname_ex(socket.gethostname())[2] if not ip.startswith("127.")][:1])

Dies funktioniert mit Python 2 und 3 unter Linux und Windows, jedoch nicht mit mehreren Netzwerkgeräten oder IPv6. Es funktionierte jedoch nicht mehr mit den neuesten Linux-Distributionen, daher habe ich stattdessen diese alternative Technik ausprobiert. Es wird versucht, eine Verbindung zum Google DNS-Server 8.8.8.8an folgendem Port herzustellen 53:

import socket
print([(s.connect(('8.8.8.8', 53)), s.getsockname()[0], s.close()) for s in [socket.socket(socket.AF_INET, socket.SOCK_DGRAM)]][0][1])

Dann kombinierte ich die beiden oben genannten Techniken zu einem Einzeiler, der überall funktionieren sollte, und erstellte den myipAlias ​​und das Python-Snippet oben in dieser Antwort.

Mit der zunehmenden Beliebtheit von IPv6 und für Server mit mehreren Netzwerkschnittstellen ist die Verwendung eines Python-Moduls eines Drittanbieters zum Ermitteln der IP-Adresse wahrscheinlich sowohl robuster als auch zuverlässiger als jede der hier aufgeführten Methoden.


2
@Alexander: Nur zu sagen, dass diese Antwort viel weniger nützlich ist als früher (und es ist nicht so, als würde man Duplikate herausfiltern;). Laut Dokumentation socket.getaddrinfo()sollte plattformübergreifend konsistent funktionieren - aber ich habe es nur unter Linux überprüft, mich nicht um andere Betriebssysteme gekümmert.
Wladimir Palant

1
@Alexander, /etc/resolve.conf: No such file or directoryund ich habe lokale IPv4-Adresse von angezeigt ifconfig.
Anatoly Techtonik

2
Ich kann bestätigen, dass die aktualisierte Version mit Ubuntu 14.04 sowohl mit Python2 als auch mit Py3k funktioniert.
Uli Köhler

4
Das "Update" zeigt einen schönen Trick mit connect () auf einem UDP-Socket. Es sendet keinen Datenverkehr, aber Sie können die Absenderadresse für Pakete an den angegebenen Empfänger ermitteln. Der Port ist wahrscheinlich irrelevant (sogar 0 sollte funktionieren). Auf einem Multihomed-Host ist es wichtig, eine Adresse im richtigen Subnetz auszuwählen.
Peter Hansen

17
Nur weil Sie diesen Code in eine einzelne Zeile schreiben können, heißt das nicht, dass Sie ...
JackLeo

91

Sie können das Netifaces- Modul verwenden. Tippe einfach:

pip install netifaces

in Ihrer Befehlsshell und es wird sich bei der Standard-Python-Installation selbst installieren.

Dann können Sie es so verwenden:

from netifaces import interfaces, ifaddresses, AF_INET
for ifaceName in interfaces():
    addresses = [i['addr'] for i in ifaddresses(ifaceName).setdefault(AF_INET, [{'addr':'No IP addr'}] )]
    print '%s: %s' % (ifaceName, ', '.join(addresses))

Auf meinem Computer wurde gedruckt:

{45639BDC-1050-46E0-9BE9-075C30DE1FBC}: 192.168.0.100
{D43A468B-F3AE-4BF9-9391-4863A4500583}: 10.5.9.207

Der Autor dieses Moduls behauptet, es sollte unter Windows, UNIX und Mac OS X funktionieren.


20
Wie in der Frage angegeben, möchte ich etwas von der Standardinstallation, da keine zusätzlichen Installationen erforderlich sind.
UnkwnTech

4
Dies wäre meine Lieblingsantwort, außer dass Netifaces IPv6 unter Windows nicht unterstützen und nicht gewartet werden. Hat jemand herausgefunden, wie man IPv6-Adressen unter Windows erhält?
Jean-Paul Calderone

3
netifaces unterstützt py3k nicht und erfordert einen C-Compiler, der unter Windows eine PITA ist.
Matt Joiner

4
@MattJoiner Keines dieser Dinge ist mehr wahr (die neueste Version hat Windows-Binärdateien auf PyPI und unterstützt Py3K).
Alastair

4
@ Jean-PaulCalderone FWIW, die neueste Version von netifaces funktioniert Unterstützung von IPv6 unter Windows.
Alastair

47

Socket-API-Methode

Siehe https://stackoverflow.com/a/28950776/711085

Nachteile:

  • Nicht plattformübergreifend.
  • Benötigt mehr Fallback-Code, der an das Vorhandensein bestimmter Adressen im Internet gebunden ist
  • Dies funktioniert auch nicht, wenn Sie sich hinter einem NAT befinden
  • Stellt wahrscheinlich eine UDP-Verbindung her, die nicht unabhängig von der DNS-Verfügbarkeit (normalerweise von ISPs) ist (Ideen wie die Verwendung von 8.8.8.8: Googles (zufällig auch DNS) Server) finden Sie in anderen Antworten.
  • Stellen Sie sicher, dass Sie die Zieladresse UNREACHABLE machen, z. B. eine numerische IP-Adresse, die garantiert nicht verwendet wird. Verwenden Sie KEINE Domain wie fakesubdomain.google.com oder somefakewebsite.com. Sie werden diese Partei immer noch (jetzt oder in Zukunft) spammen und dabei auch Ihre eigenen Netzwerkboxen spammen.

Reflektormethode

(Beachten Sie, dass dies nicht die Frage des OP nach der lokalen IP-Adresse beantwortet, z. B. 192.168 ...; Sie erhalten Ihre öffentliche IP-Adresse, die je nach Anwendungsfall möglicherweise wünschenswerter ist.)

Sie können eine Site wie whatismyip.com (jedoch mit einer API) abfragen, z.

from urllib.request import urlopen
import re
def getPublicIp():
    data = str(urlopen('http://checkip.dyndns.com/').read())
    # data = '<html><head><title>Current IP Check</title></head><body>Current IP Address: 65.96.168.198</body></html>\r\n'

    return re.compile(r'Address: (\d+\.\d+\.\d+\.\d+)').search(data).group(1)

oder wenn Sie python2 verwenden:

from urllib import urlopen
import re
def getPublicIp():
    data = str(urlopen('http://checkip.dyndns.com/').read())
    # data = '<html><head><title>Current IP Check</title></head><body>Current IP Address: 65.96.168.198</body></html>\r\n'

    return re.compile(r'Address: (\d+\.\d+\.\d+\.\d+)').search(data).group(1)

Vorteile:

  • Ein Vorteil dieser Methode ist die plattformübergreifende Methode
  • Es funktioniert hinter hässlichen NATs (zB Ihrem Heimrouter).

Nachteile (und Problemumgehungen):

  • Erfordert, dass diese Website aktiv ist, dass sich das Format nicht ändert (mit ziemlicher Sicherheit nicht) und dass Ihre DNS-Server funktionieren. Sie können dieses Problem beheben, indem Sie im Fehlerfall auch andere IP-Adressreflektoren von Drittanbietern abfragen.
  • Möglicher Angriffsvektor, wenn Sie nicht mehrere Reflektoren abfragen (um zu verhindern, dass ein kompromittierter Reflektor Ihnen mitteilt, dass Ihre Adresse nicht der Fall ist) oder wenn Sie kein HTTPS verwenden (um zu verhindern, dass ein Man-in-the-Middle-Angriff vorgibt der Server sein)

bearbeiten : Obwohl ich anfangs dachte, dass diese Methoden wirklich schlecht sind (wenn Sie nicht viele Fallbacks verwenden, kann der Code in vielen Jahren irrelevant sein), stellt sich die Frage "Was ist das Internet?". Ein Computer kann viele Schnittstellen haben, die auf viele verschiedene Netzwerke verweisen. Für eine ausführlichere Beschreibung des Themas gehen Sie auf Google fürgateways and routes. Ein Computer kann möglicherweise über ein internes Gateway auf ein internes Netzwerk zugreifen oder über ein Gateway auf beispielsweise einem Router (normalerweise der Fall) auf das World Wide Web zugreifen. Die lokale IP-Adresse, nach der das OP fragt, ist nur in Bezug auf eine einzelne Verbindungsschicht genau definiert. Sie müssen dies also angeben ("Handelt es sich um die Netzwerkkarte oder das Ethernet-Kabel?"). . Es kann mehrere nicht eindeutige Antworten auf diese Frage geben. Die globale IP-Adresse im World Wide Web ist jedoch wahrscheinlich genau definiert (ohne massive Netzwerkfragmentierung): wahrscheinlich der Rückweg über das Gateway, das auf die TLDs zugreifen kann.


Dies gibt Ihre LAN-weite Adresse zurück, wenn Sie sich hinter einem NAT befinden. Wenn Sie eine Verbindung zum Internet herstellen, können Sie eine Verbindung zu einem Webdienst herstellen, der eine Ihrer öffentlichen IP-Adressen zurückgibt.
Phihag

Es wird keine TCP-Verbindung erstellt, da eine UDP-Verbindung erstellt wird.
Anuj Gupta

2
Alternativ können Sie in der Socket-API-Version s.connect (('INSERT SOME TARGET WEBSITE.com', 0)) durch s.setsockopt (socket.SOL_SOCKET, socket.SO_BROADCAST, 1); s.connect (('<) ersetzen Broadcast> ', 0)), um eine DNS-Suche zu vermeiden. (Ich denke, es könnte ein Problem mit einer Sendung geben, wenn es eine Firewall gibt)
dlm

45

Wenn der Computer eine Route zum Internet hat, funktioniert dies immer , um die bevorzugte lokale IP-Adresse zu erhalten, auch wenn / etc / hosts nicht richtig eingestellt ist.

import socket

s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.connect(('8.8.8.8', 1))  # connect() for UDP doesn't send packets
local_ip_address = s.getsockname()[0]

wie funktioniert das ? , 8.8.8.8Ist ein Google - DNS - Server können wir es mit einem lokalen DNS - Server zu tun?
Ciasto piekarz

39

Unter Linux:

>>> import socket, struct, fcntl
>>> sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
>>> sockfd = sock.fileno()
>>> SIOCGIFADDR = 0x8915
>>>
>>> def get_ip(iface = 'eth0'):
...     ifreq = struct.pack('16sH14s', iface, socket.AF_INET, '\x00'*14)
...     try:
...         res = fcntl.ioctl(sockfd, SIOCGIFADDR, ifreq)
...     except:
...         return None
...     ip = struct.unpack('16sH2x4s8x', res)[2]
...     return socket.inet_ntoa(ip)
... 
>>> get_ip('eth0')
'10.80.40.234'
>>> 

Dies öffnet also effektiv einen Socket, mit dem es nichts zu tun hat, und Sie überprüfen die Rohdaten zu diesem Socket, um die lokale IP zu erhalten.
Dave

1
Der Socket wird geöffnet, damit ein fd mit dem Kernel (via ioctl) kommunizieren kann . Der Socket ist nicht an die Schnittstelle gebunden, für die Sie Adr-Informationen benötigen - es handelt sich lediglich um einen Kommunikationsmechanismus zwischen dem Benutzerbereich und dem Kernel. en.wikipedia.org/wiki/Ioctl lxr.free-electrons.com/source/net/socket.c
tMC

2
Funktioniert auf Python3 mit einer Modifikation: struct.pack('16sH14s', iface, socket.AF_INET, '\x00'*14)sollte durchstruct.pack('16sH14s', iface.encode('utf-8'), socket.AF_INET, b'\x00'*14)
pepoluan

1
@ChristianFischer ioctlist eine Legacy-Schnittstelle, von der ich nicht glaube, dass sie IPv6 unterstützt und wahrscheinlich niemals unterstützt. Ich denke, der "richtige" Weg führt über Netlink, was in Python nicht sehr einfach ist. Ich denke, libc sollte die Funktion haben, auf getifaddrsdie über ctypesdas Python-
tMC

1
@Maddy ioctl ist eine Legacy-Schnittstelle, von der ich nicht glaube, dass sie IPv6 unterstützt und wahrscheinlich niemals unterstützt. Ich denke, der "richtige" Weg führt über Netlink, was in Python nicht sehr einfach ist. Ich denke, libc sollte die Funktion getifaddrs haben, auf die über das Python ctypes-Modul zugegriffen werden kann, das möglicherweise funktioniert - man7.org/linux/man-pages/man3/getifaddrs.3.html
tMC

27

Ich benutze folgendes Modul:

#!/usr/bin/python
# module for getting the lan ip address of the computer

import os
import socket

if os.name != "nt":
    import fcntl
    import struct
    def get_interface_ip(ifname):
        s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        return socket.inet_ntoa(fcntl.ioctl(
                s.fileno(),
                0x8915,  # SIOCGIFADDR
                struct.pack('256s', bytes(ifname[:15], 'utf-8'))
                # Python 2.7: remove the second argument for the bytes call
            )[20:24])

def get_lan_ip():
    ip = socket.gethostbyname(socket.gethostname())
    if ip.startswith("127.") and os.name != "nt":
        interfaces = ["eth0","eth1","eth2","wlan0","wlan1","wifi0","ath0","ath1","ppp0"]
        for ifname in interfaces:
            try:
                ip = get_interface_ip(ifname)
                break;
            except IOError:
                pass
    return ip

Getestet mit Windows und Linux (und erfordert keine zusätzlichen Module für diese), die für die Verwendung auf Systemen vorgesehen sind, die sich in einem einzelnen IPv4-basierten LAN befinden.

Die feste Liste der Schnittstellennamen funktioniert nicht für neuere Linux-Versionen, die die von Alexander erwähnte Änderung systemd v197 in Bezug auf vorhersagbare Schnittstellennamen übernommen haben . In solchen Fällen müssen Sie die Liste manuell durch die Schnittstellennamen auf Ihrem System ersetzen oder eine andere Lösung wie Netifaces verwenden .


2
Dies ist nicht kompatibel mit den neuen vorhersehbaren Linux-Schnittstellennamen, wie z enp0s25. Weitere Informationen finden Sie unter wiki.archlinux.org/index.php/Network_Configuration#Device_names
Alexander

2
Ich habe Python 3.4 verwendet und der Teil 'struct.pack (...)' musste in 'struct.pack (' 256s ', Bytes (ifname [: 15],' utf-8 '))' geändert werden. Siehe diese Frage: stackoverflow.com/q/27391167/76010
Bakanekobrain

1
auf Raspbian mit Python 2.7.3 - bytes () mochte das 2. Argument nicht. Aber das hat funktioniert: struct.pack('256s', bytes(ifname[:15]))
colm.anseo

24

Ich benutze dies auf meinen Ubuntu-Maschinen:

import commands
commands.getoutput("/sbin/ifconfig").split("\n")[1].split()[1][5:]

Das funktioniert nicht.


Schön und einfach. Funktioniert auch unter Amazon Linux AMI, aber nur, wenn ich root bin. Andernfalls würde ich eine Fehlermeldung erhalten: 'sh: ifconfig: Befehl nicht gefunden'
IgorGanapolsky

Also solltest du "/ sbin / ifconfig" verwenden, wie Gavaletz sagte. Es funktioniert auch unter Red Hat 4.1.2-48.
IgorGanapolsky

7
Veraltet seit 2.6. Verwenden Sie das Unterprozessmodul , um Befehle auszuführen.
Colin Dunklau

5
Und ifconfig ist ebenfalls veraltet. Verwenden Sie iproute2.
Helmut Grohne

Holen Sie sich alle ips: import sh; [ip.split () [1] [5:] für ip im Filter (Lambda x: 'inet addr' in x, sh.ifconfig (). split ("\ n"))]
Gabriel Littman

20

Wenn Sie keine externen Pakete verwenden und sich nicht auf externe Internet-Server verlassen möchten, kann dies hilfreich sein. Es ist ein Codebeispiel, das ich in der Google-Codesuche gefunden und geändert habe, um die erforderlichen Informationen zurückzugeben:

def getIPAddresses():
    from ctypes import Structure, windll, sizeof
    from ctypes import POINTER, byref
    from ctypes import c_ulong, c_uint, c_ubyte, c_char
    MAX_ADAPTER_DESCRIPTION_LENGTH = 128
    MAX_ADAPTER_NAME_LENGTH = 256
    MAX_ADAPTER_ADDRESS_LENGTH = 8
    class IP_ADDR_STRING(Structure):
        pass
    LP_IP_ADDR_STRING = POINTER(IP_ADDR_STRING)
    IP_ADDR_STRING._fields_ = [
        ("next", LP_IP_ADDR_STRING),
        ("ipAddress", c_char * 16),
        ("ipMask", c_char * 16),
        ("context", c_ulong)]
    class IP_ADAPTER_INFO (Structure):
        pass
    LP_IP_ADAPTER_INFO = POINTER(IP_ADAPTER_INFO)
    IP_ADAPTER_INFO._fields_ = [
        ("next", LP_IP_ADAPTER_INFO),
        ("comboIndex", c_ulong),
        ("adapterName", c_char * (MAX_ADAPTER_NAME_LENGTH + 4)),
        ("description", c_char * (MAX_ADAPTER_DESCRIPTION_LENGTH + 4)),
        ("addressLength", c_uint),
        ("address", c_ubyte * MAX_ADAPTER_ADDRESS_LENGTH),
        ("index", c_ulong),
        ("type", c_uint),
        ("dhcpEnabled", c_uint),
        ("currentIpAddress", LP_IP_ADDR_STRING),
        ("ipAddressList", IP_ADDR_STRING),
        ("gatewayList", IP_ADDR_STRING),
        ("dhcpServer", IP_ADDR_STRING),
        ("haveWins", c_uint),
        ("primaryWinsServer", IP_ADDR_STRING),
        ("secondaryWinsServer", IP_ADDR_STRING),
        ("leaseObtained", c_ulong),
        ("leaseExpires", c_ulong)]
    GetAdaptersInfo = windll.iphlpapi.GetAdaptersInfo
    GetAdaptersInfo.restype = c_ulong
    GetAdaptersInfo.argtypes = [LP_IP_ADAPTER_INFO, POINTER(c_ulong)]
    adapterList = (IP_ADAPTER_INFO * 10)()
    buflen = c_ulong(sizeof(adapterList))
    rc = GetAdaptersInfo(byref(adapterList[0]), byref(buflen))
    if rc == 0:
        for a in adapterList:
            adNode = a.ipAddressList
            while True:
                ipAddr = adNode.ipAddress
                if ipAddr:
                    yield ipAddr
                adNode = adNode.next
                if not adNode:
                    break

Verwendungszweck:

>>> for addr in getIPAddresses():
>>>    print addr
192.168.0.100
10.5.9.207

Da es auf beruht windll, wird dies nur unter Windows arbeiten.


Die obige Einzeilerlösung funktioniert im Allgemeinen bei Fenstern. Es ist das Linux, das ein Problem darstellt.
Ricree

14
+1 Diese Technik versucht zumindest, alle Adressen auf dem Computer zurückzugeben.
Jason R. Coombs

1
Dieses Skript schlägt auf meinem Computer fehl, nachdem die erste Adresse zurückgegeben wurde. Fehler ist "AttributeError: 'LP_IP_ADDR_STRING' Objekt hat kein Attribut 'ipAddress'" Ich vermute, es hat etwas mit der IPv6-Adresse zu tun.
Jason R. Coombs

1
Es stellt sich heraus, dass der adNode für alles andere als die erste IP-Adresse nicht dereferenziert wird. Fügen Sie dem Beispiel in der while-Schleife eine weitere Zeile hinzu, und es funktioniert für mich: adNode = adNode.contents
Jason R. Coombs

18

Auf Debian (getestet) und ich vermute die meisten Linux ..

import commands

RetMyIP = commands.getoutput("hostname -I")

Unter MS Windows (getestet)

import socket

socket.gethostbyname(socket.gethostname())

1
Funktioniert nicht unter macOS:hostname: illegal option -- I\nusage: hostname [-fs] [name-of-host]
Derek 17 會 功夫

18

Eine Version, von der ich nicht glaube, dass sie noch veröffentlicht wurde. Ich habe mit Python 2.7 unter Ubuntu 12.04 getestet.

Diese Lösung finden Sie unter: http://code.activestate.com/recipes/439094-get-the-ip-address-associated-with-a-network-inter/

import socket
import fcntl
import struct

def get_ip_address(ifname):
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    return socket.inet_ntoa(fcntl.ioctl(
        s.fileno(),
        0x8915,  # SIOCGIFADDR
        struct.pack('256s', ifname[:15])
    )[20:24])

Beispiel Ergebnis:

>>> get_ip_address('eth0')
'38.113.228.130'

2
Funktioniert unter Python3, Ubuntu 18.04; Die Zeichenfolge muss Bytes sein: >>> socket.inet_ntoa (fcntl.ioctl (s.fileno (), 0x8915, struct.pack ('256s', 'enp0s31f6' [: 15] .encode ('utf-8')) )) [20:24]) '192.168.1.1'
cessor

12

Variation der Antwort von Ninjagecko. Dies sollte in jedem LAN funktionieren, das UDP-Broadcast ermöglicht und keinen Zugriff auf eine Adresse im LAN oder Internet erfordert.

import socket
def getNetworkIp():
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
    s.connect(('<broadcast>', 0))
    return s.getsockname()[0]

print (getNetworkIp())

Warten Sie, wie ist <broadcast>ein gültiger Hostname? !! Wie viele dieser verbalen Hostnamen sind gültig?
Dev Aggarwal

Dies funktioniert für mich unter Ubuntu 20.04 - 192.168.0.24 nicht 127.0.0.1
Lewis Morris vor

8

Ich fürchte, es gibt keine guten plattformunabhängigen Möglichkeiten, dies zu tun, außer eine Verbindung zu einem anderen Computer herzustellen und Ihnen Ihre IP-Adresse zu senden. Zum Beispiel: findmyipaddress . Beachten Sie, dass dies nicht funktioniert, wenn Sie eine IP-Adresse benötigen, die sich hinter NAT befindet, es sei denn, der Computer, mit dem Sie eine Verbindung herstellen, befindet sich ebenfalls hinter NAT.

Hier ist eine Lösung, die unter Linux funktioniert: Rufen Sie die IP-Adresse ab, die einer Netzwerkschnittstelle zugeordnet ist .


8

Eine einfache Möglichkeit, eine "saubere" Ausgabe über Befehlszeilenprogramme zu erstellen:

import commands
ips = commands.getoutput("/sbin/ifconfig | grep -i \"inet\" | grep -iv \"inet6\" | " +
                         "awk {'print $2'} | sed -ne 's/addr\:/ /p'")
print ips

Es werden alle IPv4-Adressen auf dem System angezeigt.


1
Es werden nicht alle IPv4-Adressen angezeigt, da ifconfig nur über primäre Adressen informiert. Sie müssen "ip" von iproute2 verwenden, um alle Adressen anzuzeigen.
Helmut Grohne

Das ist eine Menge Shell für eine Frage nach der Standardbibliothek… Außerdem ist das Parsen von ifconfig weder portabel noch funktioniert es nicht einmal zuverlässig auf einem Computer.
Dominik George

7

Zu Ihrer Information Ich kann überprüfen, ob die Methode:

import socket
addr = socket.gethostbyname(socket.gethostname())

Funktioniert unter OS X (10.6.10.5), Windows XP und auf einem gut verwalteten RHEL-Abteilungsserver. Es funktionierte nicht auf einer sehr minimalen CentOS-VM, auf der ich nur Kernel-Hacking mache. In diesem Fall können Sie einfach nach einer 127.0.0.1-Adresse suchen und in diesem Fall Folgendes tun:

if addr == "127.0.0.1":
     import commands
     output = commands.getoutput("/sbin/ifconfig")
     addr = parseaddress(output)

Und dann analysieren Sie die IP-Adresse von der Ausgabe. Es sollte beachtet werden, dass ifconfig standardmäßig nicht im PATH eines normalen Benutzers enthalten ist, und deshalb gebe ich den vollständigen Pfad im Befehl an. Ich hoffe das hilft.


7

Dies ist eine Variante der Antwort von UnkwnTech - sie bietet eine get_local_addr()Funktion, die die primäre LAN-IP-Adresse des Hosts zurückgibt. Ich poste es, weil dies eine Reihe von Dingen hinzufügt: IPv6-Unterstützung, Fehlerbehandlung, Ignorieren von localhost / linklocal-Adressen und Verwenden einer TESTNET-Adresse (rfc5737) zum Herstellen einer Verbindung.

# imports
import errno
import socket
import logging

# localhost prefixes
_local_networks = ("127.", "0:0:0:0:0:0:0:1")

# ignore these prefixes -- localhost, unspecified, and link-local
_ignored_networks = _local_networks + ("0.", "0:0:0:0:0:0:0:0", "169.254.", "fe80:")

def detect_family(addr):
    if "." in addr:
        assert ":" not in addr
        return socket.AF_INET
    elif ":" in addr:
        return socket.AF_INET6
    else:
        raise ValueError("invalid ipv4/6 address: %r" % addr)

def expand_addr(addr):
    """convert address into canonical expanded form --
    no leading zeroes in groups, and for ipv6: lowercase hex, no collapsed groups.
    """
    family = detect_family(addr)
    addr = socket.inet_ntop(family, socket.inet_pton(family, addr))
    if "::" in addr:
        count = 8-addr.count(":")
        addr = addr.replace("::", (":0" * count) + ":")
        if addr.startswith(":"):
            addr = "0" + addr
    return addr

def _get_local_addr(family, remote):
    try:
        s = socket.socket(family, socket.SOCK_DGRAM)
        try:
            s.connect((remote, 9))
            return s.getsockname()[0]
        finally:
            s.close()
    except socket.error:
        # log.info("trapped error connecting to %r via %r", remote, family, exc_info=True)
        return None

def get_local_addr(remote=None, ipv6=True):
    """get LAN address of host

    :param remote:
        return  LAN address that host would use to access that specific remote address.
        by default, returns address it would use to access the public internet.

    :param ipv6:
        by default, attempts to find an ipv6 address first.
        if set to False, only checks ipv4.

    :returns:
        primary LAN address for host, or ``None`` if couldn't be determined.
    """
    if remote:
        family = detect_family(remote)
        local = _get_local_addr(family, remote)
        if not local:
            return None
        if family == socket.AF_INET6:
            # expand zero groups so the startswith() test works.
            local = expand_addr(local)
        if local.startswith(_local_networks):
            # border case where remote addr belongs to host
            return local
    else:
        # NOTE: the two addresses used here are TESTNET addresses,
        #       which should never exist in the real world.
        if ipv6:
            local = _get_local_addr(socket.AF_INET6, "2001:db8::1234")
            # expand zero groups so the startswith() test works.
            if local:
                local = expand_addr(local)
        else:
            local = None
        if not local:
            local = _get_local_addr(socket.AF_INET, "192.0.2.123")
            if not local:
                return None
    if local.startswith(_ignored_networks):
        return None
    return local

Ich dachte, das hätte eine wirklich gute Antwort sein können ... aber es kehrt immer wieder zurückNone
Jamie Lindsey

@JamieLindsey Haben Sie einige Details zu Ihrem Betriebssystem und der Netzwerkkonfiguration? Und was bringt so etwas wie get_local_addr(remove="www.google.com")Rückkehr? Das Protokollieren des socket.errorvon _get_local_addr () ausgelösten Protokolls kann bei der Diagnose hilfreich sein.
Eli Collins

6
import socket
[i[4][0] for i in socket.getaddrinfo(socket.gethostname(), None)]

1
Hmm ... auf einem Server mit zwei Netzwerkkarten gibt dies eine der zugewiesenen IP-Adressen an, wird jedoch dreimal wiederholt. Auf meinem Laptop gibt es '127.0.1.1' (dreimal wiederholt ...) ...
bryn

Gibt mir ['fe80::34e8:fe19:1459:2cde%22','fe80::d528:99fb:d572:e289%12', '192.168.56.1', '192.168.1.2']auf Windows-Desktop.
Nakilon

5

Dies funktioniert auf den meisten Linux-Boxen:

import socket, subprocess, re
def get_ipv4_address():
    """
    Returns IP address(es) of current machine.
    :return:
    """
    p = subprocess.Popen(["ifconfig"], stdout=subprocess.PIPE)
    ifc_resp = p.communicate()
    patt = re.compile(r'inet\s*\w*\S*:\s*(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})')
    resp = patt.findall(ifc_resp[0])
    print resp

get_ipv4_address()

5

Diese Antwort ist mein persönlicher Versuch, das Problem des Abrufs der LAN-IP zu lösen, da socket.gethostbyname(socket.gethostname())auch 127.0.0.1 zurückgegeben wurde. Diese Methode erfordert nicht nur eine LAN-Verbindung zum Internet. Code ist für Python 3.x, kann aber leicht für 2.x konvertiert werden. Verwenden von UDP Broadcast:

import select
import socket
import threading
from queue import Queue, Empty

def get_local_ip():
        def udp_listening_server():
            s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
            s.bind(('<broadcast>', 8888))
            s.setblocking(0)
            while True:
                result = select.select([s],[],[])
                msg, address = result[0][0].recvfrom(1024)
                msg = str(msg, 'UTF-8')
                if msg == 'What is my LAN IP address?':
                    break
            queue.put(address)

        queue = Queue()
        thread = threading.Thread(target=udp_listening_server)
        thread.queue = queue
        thread.start()
        s2 = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        s2.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
        waiting = True
        while waiting:
            s2.sendto(bytes('What is my LAN IP address?', 'UTF-8'), ('<broadcast>', 8888))
            try:
                address = queue.get(False)
            except Empty:
                pass
            else:
                waiting = False
        return address[0]

if __name__ == '__main__':
    print(get_local_ip())

1
Was passiert, wenn Sie dies gleichzeitig auf zwei Computern im selben Netzwerk ausführen? Während Sie Ihre Nachricht im Netzwerk senden, erhalten alle Computer die Meldung "Was ist meine LAN-IP-Adresse?". Ihr udp_listening_server könnte auf die Nachricht antworten, dass Ihre IP-Adresse xxx ist.
Nicolas Defranoux

4

127.0.1.1 ist Ihre echte IP-Adresse. Allgemeiner kann ein Computer eine beliebige Anzahl von IP-Adressen haben. Sie können sie nach privaten Netzwerken filtern - 127.0.0.0/8, 10.0.0.0/8, 172.16.0.0/12 und 192.168.0.0/16.

Es gibt jedoch keine plattformübergreifende Möglichkeit, alle IP-Adressen abzurufen. Unter Linux können Sie das SIOCGIFCONFioctl verwenden.


2
Er meint seine äußerlich sichtbare IP. Der Bereich 127. *. *. * Bezieht sich normalerweise auf localhost oder ein internes Netzwerk, was eindeutig nicht das ist, was er will.
Cerin

4

Eine geringfügige Verfeinerung der Befehlsversion, die den IP-Befehl verwendet und IPv4- und IPv6-Adressen zurückgibt:

import commands,re,socket

#A generator that returns stripped lines of output from "ip address show"
iplines=(line.strip() for line in commands.getoutput("ip address show").split('\n'))

#Turn that into a list of IPv4 and IPv6 address/mask strings
addresses1=reduce(lambda a,v:a+v,(re.findall(r"inet ([\d.]+/\d+)",line)+re.findall(r"inet6 ([\:\da-f]+/\d+)",line) for line in iplines))
#addresses1 now looks like ['127.0.0.1/8', '::1/128', '10.160.114.60/23', 'fe80::1031:3fff:fe00:6dce/64']

#Get a list of IPv4 addresses as (IPstring,subnetsize) tuples
ipv4s=[(ip,int(subnet)) for ip,subnet in (addr.split('/') for addr in addresses1 if '.' in addr)]
#ipv4s now looks like [('127.0.0.1', 8), ('10.160.114.60', 23)]

#Get IPv6 addresses
ipv6s=[(ip,int(subnet)) for ip,subnet in (addr.split('/') for addr in addresses1 if ':' in addr)]

4

Nun, Sie können den Befehl "ip route" unter GNU / Linux verwenden, um Ihre aktuelle IP-Adresse zu ermitteln.

Hier wird die IP angezeigt, die der DHCP-Server, der auf dem Router / Modem ausgeführt wird, an die Schnittstelle gesendet hat. Normalerweise ist "192.168.1.1/24" die IP für das lokale Netzwerk, wobei "24" den Bereich möglicher IP-Adressen bedeutet, die vom DHCP-Server innerhalb des Maskenbereichs angegeben werden.

Hier ein Beispiel: Beachten Sie, dass PyNotify nur eine Ergänzung ist, um meinen Standpunkt klar zu machen, und überhaupt nicht erforderlich ist

#! /usr/bin/env python

import sys , pynotify

if sys.version_info[1] != 7:
   raise RuntimeError('Python 2.7 And Above Only')       

from subprocess import check_output # Available on Python 2.7+ | N/A 

IP = check_output(['ip', 'route'])
Split_Result = IP.split()

# print Split_Result[2] # Remove "#" to enable

pynotify.init("image")
notify = pynotify.Notification("Ip", "Server Running At:" + Split_Result[2] , "/home/User/wireless.png")    
notify.show()    

Dies hat den Vorteil, dass Sie die Netzwerkschnittstelle nicht angeben müssen. Das ist ziemlich nützlich, wenn Sie einen Socket-Server ausführen

Sie können PyNotify mit easy_install oder sogar Pip installieren:

easy_install py-notify

oder

pip install py-notify

oder innerhalb von Python Script / Interpreter

from pip import main

main(['install', 'py-notify'])

4

Wenn Sie nach einer IPV4-Adresse suchen, die sich von Ihrer lokalen Host-IP-Adresse unterscheidet 127.0.0.1, finden Sie hier einen ordentlichen Python-Code:

import subprocess
address = subprocess.check_output(['hostname', '-s', '-I'])
address = address.decode('utf-8') 
address=address[:-1]

Was auch in einer einzigen Zeile geschrieben werden kann:

address = subprocess.check_output(['hostname', '-s', '-I']).decode('utf-8')[:-1]

Auch wenn Sie setzen localhostin /etc/hostnameIhrer lokale IP - Adresse, wird der Code immer noch geben.


4

Für Linux können Sie einfach check_outputden hostname -ISystembefehl wie folgt verwenden:

from subprocess import check_output
check_output(['hostname', '-I'])

Ich weiß, dass die Frage für Googler eine plattformübergreifende Lösung war
Kasper Skytte Andersen

3

Hinweis: Dies verwendet nicht die Standardbibliothek, ist aber recht einfach.

$ pip install pif

from pif import get_public_ip
get_public_ip()

3
Die Fragen betrafen das Finden der IP mit stdlib
Alexandru Chirila

3

netifaces ist über pip und easy_install verfügbar. (Ich weiß, es ist nicht in der Basis, aber es könnte die Installation wert sein.)

netifaces hat plattformübergreifende Besonderheiten:

  • Die localhost / loop-back-Schnittstelle ist möglicherweise nicht immer enthalten (Cygwin).
  • Adressen werden pro Protokoll (z. B. IPv4, IPv6) und Protokolle pro Schnittstelle aufgelistet. Auf einigen Systemen (Linux) hat jedes Protokoll-Schnittstellen-Paar eine eigene zugeordnete Schnittstelle (unter Verwendung der Notation interface_name: n), während auf anderen Systemen (Windows) eine einzelne Schnittstelle eine Adressliste für jedes Protokoll enthält. In beiden Fällen gibt es eine Protokollliste, die jedoch möglicherweise nur ein einziges Element enthält.

Hier ist ein Netifaces-Code zum Spielen:

import netifaces

PROTO = netifaces.AF_INET   # We want only IPv4, for now at least

# Get list of network interfaces
# Note: Can't filter for 'lo' here because Windows lacks it.
ifaces = netifaces.interfaces()

# Get all addresses (of all kinds) for each interface
if_addrs = [netifaces.ifaddresses(iface) for iface in ifaces]

# Filter for the desired address type
if_inet_addrs = [addr[PROTO] for addr in if_addrs if PROTO in addr]

iface_addrs = [s['addr'] for a in if_inet_addrs for s in a if 'addr' in s]
# Can filter for '127.0.0.1' here.

Der obige Code ordnet eine Adresse nicht ihrem Schnittstellennamen zu (nützlich zum schnellen Generieren von ebtables / iptables-Regeln). Hier ist eine Version, die die obigen Informationen mit dem Schnittstellennamen in einem Tupel enthält:

import netifaces

PROTO = netifaces.AF_INET   # We want only IPv4, for now at least

# Get list of network interfaces
ifaces = netifaces.interfaces()

# Get addresses for each interface
if_addrs = [(netifaces.ifaddresses(iface), iface) for iface in ifaces]

# Filter for only IPv4 addresses
if_inet_addrs = [(tup[0][PROTO], tup[1]) for tup in if_addrs if PROTO in tup[0]]

iface_addrs = [(s['addr'], tup[1]) for tup in if_inet_addrs for s in tup[0] if 'addr' in s]

Und nein, ich bin nicht verliebt in Listenverständnisse. So funktioniert mein Gehirn heutzutage.

Das folgende Snippet druckt alles aus:

from __future__ import print_function  # For 2.x folks
from pprint import pprint as pp

print('\nifaces = ', end='')
pp(ifaces)

print('\nif_addrs = ', end='')
pp(if_addrs)

print('\nif_inet_addrs = ', end='')
pp(if_inet_addrs)

print('\niface_addrs = ', end='')
pp(iface_addrs)

Genießen!


netifaces erleichtert das Leben sehr, wenn es um dieses Problem geht.
Drake Guan

3

Eine Python 3.4-Version, die das neu eingeführte Asyncio-Paket verwendet.

async get_local_ip():
    loop = asyncio.get_event_loop()
    transport, protocol = await loop.create_datagram_endpoint(
        asyncio.DatagramProtocol,
        remote_addr=('8.8.8.8', 80))
    result = transport.get_extra_info('sockname')[0])
    transport.close()
    return result

Dies basiert auf der hervorragenden Antwort von UnkwnTech .


3

Um die IP-Adresse zu erhalten, können Sie einen Shell-Befehl direkt in Python verwenden :

import socket, subprocess

def getIpAndHostname():
    hostname =  socket.gethostname()

    shell_cmd = "ifconfig | awk '/inet addr/{print substr($2,6)}'"
    proc = subprocess.Popen([shell_cmd], stdout=subprocess.PIPE, shell=True)
    (out, err) = proc.communicate()

    ip_list = out.split('\n')
    ip = ip_list[0]

    for _ip in ip_list:
        try:
            if _ip != "127.0.0.1" and _ip.split(".")[3] != "1":
                ip = _ip
        except:
            pass
    return ip, hostname

ip_addr, hostname = getIpAndHostname()
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.