Trovare gli indirizzi IP locali usando lo stdlib di Python


547

Come posso trovare gli indirizzi IP locali (ovvero 192.168.xx o 10.0.xx) nella piattaforma Python in modo indipendente e usando solo la libreria standard?


7
L'IP locale? O IP pubblico? Come gestirai i sistemi con più IP?
Sargun Dhillon,

usa ifconfig -ae usa l'output da lì ...
Fredrik Pihl,

16
@Fredrik Questa è una cattiva idea. Prima di tutto, stai forzando inutilmente un nuovo processo e questo potrebbe impedire al tuo programma di funzionare in configurazioni strettamente bloccate (o, dovrai consentire i diritti di cui il tuo programma non ha bisogno). In secondo luogo, introdurre bug per gli utenti di diverse lingue. In terzo luogo, se decidi di avviare un nuovo programma, non dovresti avviarne uno obsoleto: ip addrè molto più adatto (e più facile da analizzare, da avviare).
phihag,

12
@phihag hai assolutamente ragione, grazie per aver corretto la mia stupidità
Fredrik Pihl,

1
Un problema più fondamentale qui è che in un moderno programma di rete ben scritto il giusto (set di) indirizzo / i IP locale dipende dal peer o dal set di potenziali peer. Se l'indirizzo IP locale è necessario per bindun socket a una particolare interfaccia, è una questione politica. Se è necessario l'indirizzo IP locale per consegnarlo a un peer in modo che il peer possa "richiamare", ovvero per riaprire una connessione al computer locale, la situazione dipende dalla presenza di NAT (Network Address Translation) scatole in mezzo. Se non ci sono NAT, getsocknameè una buona scelta.
Pekka Nikander,

Risposte:


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

Questo non funzionerà sempre (ritorna 127.0.0.1su macchine con il nome host in /etc/hostsas 127.0.0.1), un paliative sarebbe ciò che gimel mostra, usare socket.getfqdn()invece. Ovviamente la tua macchina ha bisogno di un nome host risolvibile.


43
Si noti che questa non è una soluzione indipendente dalla piattaforma. Molti Linux restituiranno 127.0.0.1 come indirizzo IP usando questo metodo.
Jason Baker,

20
Una variante: socket.gethostbyname (socket.getfqdn ())
gimel,

55
Questo sembra restituire solo un singolo indirizzo IP. Cosa succede se la macchina ha più indirizzi?
Jason R. Coombs,

26
Su Ubuntu questo restituisce 127.0.1.1 per qualche motivo.
Scorre il

13
@Jason R. Coombs, utilizzare il seguente codice per recuperare un elenco di indirizzi IPv4 che appartengono alla macchina host:socket.gethostbyname_ex(socket.gethostname())[-1]
Barmaley,

460

Ho appena trovato questo, ma sembra un po 'hacker, tuttavia dicono che l'ho provato su * nix e l'ho fatto su Windows e ha funzionato.

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

Ciò presuppone che tu abbia un accesso a Internet e che non vi sia alcun proxy locale.


31
Bello se hai diverse interfacce sulla macchina e hai bisogno di quella che instrada ad es
Gmail.com

4
Potrebbe essere una buona idea catturare le eccezioni socket.error che possono essere sollevate da s.connect ()!
phobie,

39
Sarebbe meglio usare l'indirizzo IP invece di un nome di dominio - deve essere più veloce e indipendente dalla disponibilità DNS. Ad esempio, possiamo utilizzare 8.8.8.8 IP - il server DNS pubblico di Google.
Wobmene,

10
Molto intelligente, funziona perfettamente. Invece di Gmail o 8.8.8.8, puoi anche usare l'indirizzo IP o l'indirizzo del server da cui vuoi essere visto, se applicabile.
contratto del Prof. Falken è stato violato il

3
Questo esempio ha una dipendenza esterna di poter effettivamente risolvere gmail.com. Se lo si imposta su un indirizzo IP non presente nella propria LAN locale (non importa se è attivo o inattivo) funzionerà senza dipendenze e senza traffico di rete.
cupo

254

Questo metodo restituisce l'IP "primario" nella casella locale (quello con una route predefinita) .

  • NON necessita di accesso alla rete instradabile o di qualsiasi connessione.
  • Funziona anche se tutte le interfacce sono scollegate dalla rete.
  • NON ha bisogno o cerca di arrivare altrove .
  • Funziona con NAT, IP pubblici, privati, esterni e interni
  • Pure Python 2 (o 3) senza dipendenze esterne.
  • Funziona su Linux, Windows e OSX.

Python 3 o 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

Ciò restituisce un singolo IP che è il principale (quello con una route predefinita). Se invece hai bisogno di tutti gli IP collegati a tutte le interfacce (incluso localhost, ecc.), Vedi questa risposta .

Se sei dietro un firewall NAT come il tuo wifi box a casa, questo non mostrerà il tuo IP NAT pubblico, ma invece il tuo IP privato sulla rete locale che ha un percorso predefinito al tuo router WIFI locale; ottenere l'IP esterno del tuo router wifi richiederebbe di eseguirlo su QUESTO box o di collegarti a un servizio esterno come whatismyip.com/whatismyipaddress.com che potrebbe riflettere l'IP ... ma è completamente diverso dalla domanda originale. :)


7
Funziona in Raspbian con Python 2 e 3!
pierce.jason,

3
Brillante. Funziona su Win7,8,8,1 + Linux Mint & Arch, comprese le macchine virtuali.
Shermy

2
Funziona con Windows 10 Pro! Grazie Jamieson Becker!
varantes,

3
Per qualche motivo questo non funziona su Mac OS X El Capitan 10.11.6 (genera un errore del sistema operativo di eccezione: [Errno 49] Impossibile assegnare l'indirizzo richiesto). Cambiare la porta da '0' a '1': s.connect (('10.255.255.255', 1)) ha funzionato per me su Mac OS X e Linux Ubuntu 17.04
Pedro Scarapicchia Junior

10
Questa dovrebbe essere la risposta accettata. socket.gethostbyname(socket.gethostname())dà risultati orribili.
Jason Floyd,

142

Come un alias chiamato myip, dovrebbe funzionare ovunque:

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])'"
  • Funziona correttamente con Python 2.x, Python 3.x, distribuzioni Linux moderne e precedenti, OSX / macOS e Windows per trovare l'indirizzo IPv4 corrente.
  • Non restituirà il risultato corretto per macchine con più indirizzi IP, IPv6, nessun indirizzo IP configurato o nessun accesso a Internet.

Come sopra, ma solo il codice Python:

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])
  • Ciò genererà un'eccezione se non è configurato alcun indirizzo IP.

Versione che funziona anche su LAN senza connessione a Internet:

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])

(grazie @ccpizza )


Contesto :

L'uso socket.gethostbyname(socket.gethostname())non ha funzionato qui, perché uno dei computer su cui mi trovavo aveva /etc/hostsvoci e riferimenti duplicati su se stesso. socket.gethostbyname()restituisce solo l'ultima voce in /etc/hosts.

Questo è stato il mio tentativo iniziale, che elimina tutti gli indirizzi che iniziano con "127.":

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

Funziona con Python 2 e 3, su Linux e Windows, ma non si occupa di diversi dispositivi di rete o IPv6. Tuttavia, ha smesso di funzionare su recenti distribuzioni Linux, quindi ho provato questa tecnica alternativa. Tenta di connettersi al server DNS di Google 8.8.8.8alla porta53 :

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])

Quindi ho combinato le due tecniche di cui sopra in un one-liner che dovrebbe funzionare ovunque e ho creato il myip alias e lo snippet Python in cima a questa risposta.

Con la crescente popolarità di IPv6 e per i server con più interfacce di rete, l'utilizzo di un modulo Python di terze parti per trovare l'indirizzo IP è probabilmente sia più robusto che affidabile rispetto a qualsiasi dei metodi elencati qui.


2
@Alexander: Solo dire che questa risposta è molto meno utile di prima (e non è come filtrare i duplicati è un grosso problema;). Secondo la documentazione socket.getaddrinfo()dovrebbe funzionare in modo coerente su tutte le piattaforme, ma l'ho verificato solo su Linux, non mi sono preoccupato di nessun altro sistema operativo.
Wladimir Palant,

1
@Alexander /etc/resolve.conf: No such file or directorye ho un indirizzo IPv4 locale mostrato da ifconfig.
Anatoly Techtonik,

2
Posso confermare che la versione aggiornata funziona con Ubuntu 14.04 sia con Python2 che con Py3k.
Uli Köhler,

4
L '"aggiornamento" mostra un bel trucco con connect () su un socket UDP. Non invia traffico ma ti consente di trovare l'indirizzo del mittente per i pacchetti al destinatario specificato. La porta è probabilmente irrilevante (anche 0 dovrebbe funzionare). Su un host multihomed è importante scegliere un indirizzo nella sottorete corretta.
Peter Hansen,

17
solo perché puoi scrivere quel codice su una sola riga, non significa che dovresti ...
JackLeo,

91

È possibile utilizzare il modulo netifaces . Basta digitare:

pip install netifaces

nella tua shell dei comandi e si installerà automaticamente sull'installazione predefinita di Python.

Quindi puoi usarlo in questo modo:

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))

Sul mio computer ha stampato:

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

L'autore di questo modulo afferma che dovrebbe funzionare su Windows, UNIX e Mac OS X.


20
Come indicato nella domanda, desidero qualcosa dall'installazione predefinita, poiché non sono necessarie installazioni aggiuntive.
UnkwnTech,

4
Questa sarebbe la mia risposta preferita, tranne per il fatto che netifaces non supporta IPv6 su Windows e sembra non mantenuto. Qualcuno ha capito come ottenere gli indirizzi IPv6 su Windows?
Jean-Paul Calderone,

3
netifaces non supporta py3k e richiede un compilatore C che è un PITA su Windows.
Matt Joiner,

4
@MattJoiner Nessuna di queste cose è più vera (l'ultima versione ha i binari di Windows su PyPI e supporta Py3K).
alastair,

4
@ Jean-PaulCalderone FWIW, l'ultima versione di netifaces fa supporto IPv6 su Windows.
alastair,

47

Metodo Socket API

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

Svantaggi:

  • Non multipiattaforma.
  • Richiede più codice di fallback, legato all'esistenza di indirizzi particolari su Internet
  • Questo non funzionerà anche se sei dietro un NAT
  • Probabilmente crea una connessione UDP, non indipendente dalla disponibilità DNS (di solito dell'ISP) (vedi altre risposte per idee come l'utilizzo dell'8.8.8.8: il server di Google (per coincidenza anche DNS))
  • Assicurati di rendere INDIRIZZABILE l'indirizzo di destinazione, come un indirizzo IP numerico a cui è garantito che le specifiche non saranno utilizzate. NON utilizzare alcuni domini come fakesubdomain.google.com o somefakewebsite.com; continuerai a spammare quella parte (ora o in futuro) e anche a spammare le tue caselle di rete.

Metodo del riflettore

(Si noti che ciò non risponde alla domanda dell'OP dell'indirizzo IP locale, ad es. 192.168 ...; ti dà il tuo indirizzo IP pubblico, che potrebbe essere più desiderabile a seconda del caso d'uso.)

Puoi interrogare alcuni siti come whatismyip.com (ma con un'API), come:

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)

o se si utilizza python2:

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)

vantaggi:

  • Un aspetto positivo di questo metodo è la multipiattaforma
  • Funziona da dietro brutte NAT (ad esempio il tuo router di casa).

Svantaggi (e soluzioni alternative):

  • Richiede che questo sito Web sia attivo, che il formato non cambi (quasi sicuramente non lo farà) e che i server DNS funzionino. Si può mitigare questo problema interrogando anche altri riflettori di indirizzi IP di terze parti in caso di guasto.
  • Possibile vettore di attacco se non si interrogano più riflettori (per impedire a un riflettore compromesso di dirti che il tuo indirizzo è qualcosa che non è), o se non usi HTTPS (per impedire un attacco man-in-the-middle che finge essere il server)

modifica : Sebbene inizialmente pensassi che questi metodi fossero davvero cattivi (a meno che non si utilizzino molti fallback, il codice potrebbe essere irrilevante tra molti anni), pone la domanda "cos'è Internet?". Un computer può avere molte interfacce che puntano a molte reti diverse. Per una descrizione più approfondita dell'argomento, google pergateways and routes . Un computer può essere in grado di accedere a una rete interna tramite un gateway interno o di accedere al Web in tutto il mondo tramite un gateway, ad esempio un router (in genere il caso). L'indirizzo IP locale richiesto dall'OP è ben definito rispetto a un singolo livello di collegamento, quindi è necessario specificare che ("è la scheda di rete o il cavo Ethernet, di cui stiamo parlando?") . Potrebbero esserci più risposte non uniche a questa domanda, come proposto. Tuttavia, l'indirizzo IP globale sulla rete mondiale è probabilmente ben definito (in assenza di una massiccia frammentazione della rete): probabilmente il percorso di ritorno tramite il gateway che può accedere ai TLD.


Questo restituirà il tuo indirizzo LAN se sei dietro un NAT. Se ti stai collegando a Internet, puoi connetterti a un servizio Web che restituisce uno dei tuoi indirizzi IP pubblici.
phihag,

Non crea una connessione TCP perché crea una connessione UDP.
Anuj Gupta,

2
In alternativa alla versione dell'API socket, sostituire s.connect (('INSERT SOME TARGET WEBSITE.com', 0)) con s.setsockopt (socket.SOL_SOCKET, socket.SO_BROADCAST, 1); s.connect (('< broadcast> ', 0)) per evitare la ricerca DNS. (Suppongo che potrebbe esserci un problema con una trasmissione se c'è un firewall)
dlm

45

Se il computer ha un percorso verso Internet, funzionerà sempre per ottenere l'indirizzo IP locale preferito, anche se / etc / hosts non è impostato correttamente.

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]

come funziona ? , 8.8.8.8è un server DNS di Google possiamo farlo con un server DNS locale?
Ciasto piekarz,

39

Su 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'
>>> 

Quindi questo apre effettivamente un socket con cui non fa nulla e controlli i dati grezzi su quel socket per ottenere l'IP locale?
Dave,

1
Il socket viene aperto per ottenere un fd per comunicare con il kernel (tramite ioctl). Il socket non è associato all'interfaccia per la quale vuoi aggiungere informazioni addr - è solo un meccanismo di comunicazione tra userspace e il kernel. it.wikipedia.org/wiki/Ioctl lxr.free-electrons.com/source/net/socket.c
tMC

2
Funziona su Python3 con una modifica: struct.pack('16sH14s', iface, socket.AF_INET, '\x00'*14)dovrebbe essere sostituito construct.pack('16sH14s', iface.encode('utf-8'), socket.AF_INET, b'\x00'*14)
pepoluan il

1
@ChristianFischer ioctlè un'interfaccia legacy che non credo supporti IPv6 e probabilmente non lo farà mai. Penso che il modo "giusto" sia tramite Netlink che non è molto semplice in Python. Penso che libc dovrebbe avere la funzione a getifaddrscui è possibile accedere tramite il ctypesmodulo Pythons
tMC

1
@Maddy ioctl è un'interfaccia legacy che non credo supporti IPv6 e probabilmente non lo farà mai. Penso che il modo "giusto" sia tramite Netlink che non è molto semplice in Python. Penso che libc dovrebbe avere la funzione getifaddrs a cui è possibile accedere tramite il modulo pythons ctypes che potrebbe funzionare - man7.org/linux/man-pages/man3/getifaddrs.3.html
tMC

27

sto usando il seguente modulo:

#!/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

Testato con Windows e Linux (e non richiede moduli aggiuntivi per quelli) destinati all'uso su sistemi che si trovano in una singola LAN basata su IPv4.

L'elenco fisso di nomi di interfaccia non funziona per le recenti versioni di Linux, che hanno adottato la modifica di systemd v197 per quanto riguarda i nomi di interfaccia prevedibili come sottolineato da Alexander . In questi casi, è necessario sostituire manualmente l'elenco con i nomi delle interfacce sul proprio sistema o utilizzare un'altra soluzione come netifaces .


2
Ciò è incompatibile con i nuovi nomi di interfaccia Linux prevedibili, come ad esempio enp0s25. Per maggiori informazioni, vedi wiki.archlinux.org/index.php/Network_Configuration#Device_names
Alexander

2
Stavo usando python 3.4 e la parte 'struct.pack (...)' doveva essere cambiata in 'struct.pack (' 256s ', byte (ifname [: 15],' utf-8 '))'. Vedere questa domanda: stackoverflow.com/q/27391167/76010
Bakanekobrain

1
su Raspbian con Python 2.7.3 - bytes () non è piaciuto il secondo argomento. Ma ha funzionato: struct.pack('256s', bytes(ifname[:15]))
colm.anseo,

24

Lo uso sui miei computer Ubuntu:

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

Questo non funziona


Bello e semplice. Funziona anche su AMI Linux di Amazon, ma solo se sono root. Altrimenti
otterrei

Quindi dovresti usare "/ sbin / ifconfig" come ha detto gavaletz. Funziona anche su Red Hat 4.1.2-48.
IgorGanapolsky,

7
Obsoleto dal 2.6. Utilizzare il modulo di sottoprocesso per eseguire i comandi.
Colin Dunklau,

5
E ifconfig è anche deprecato. Usa iproute2.
Helmut Grohne,

Ottieni tutti gli ips: import sh; [ip.split () [1] [5:] per filtro ip in (lambda x: 'inet addr' in x, sh.ifconfig (). split ("\ n"))]
Gabriel Littman

20

Se non si desidera utilizzare pacchetti esterni e non si desidera fare affidamento su server Internet esterni, questo potrebbe essere d'aiuto. È un esempio di codice che ho trovato su Ricerca codice Google e modificato per restituire le informazioni richieste:

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

Uso:

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

Come si basa windll, questo funzionerà solo su Windows.


L'unica soluzione di liner sopra funziona generalmente su Windows. È quello Linux ad essere un problema.
Ricree

14
+1 Questa tecnica tenta almeno di restituire tutti gli indirizzi sulla macchina.
Jason R. Coombs,

1
Questo script non riesce sulla mia macchina dopo aver restituito il primo indirizzo. L'errore è "AttributeError: l'oggetto 'LP_IP_ADDR_STRING' non ha attributo 'ipAddress'" Sospetto che abbia qualcosa a che fare con l'indirizzo IPv6.
Jason R. Coombs,

1
Si scopre che il problema è che per tutto tranne che per il primo indirizzo IP, l'adNode non è sottovalutato. Aggiungi un'altra riga all'esempio nel ciclo while e funziona per me: adNode = adNode.contents
Jason R. Coombs

18

Su Debian (testato) e sospetto che la maggior parte di Linux ...

import commands

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

Su MS Windows (testato)

import socket

socket.gethostbyname(socket.gethostname())

1
Non funziona su macOS:hostname: illegal option -- I\nusage: hostname [-fs] [name-of-host]
Derek 朕 會 功夫

18

Una versione che non credo sia stata ancora pubblicata. Ho provato con Python 2.7 su Ubuntu 12.04.

Trovata questa soluzione su: 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])

Risultato di esempio:

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

2
Funziona su Python3, Ubuntu 18.04; La stringa deve essere byte: >>> socket.inet_ntoa (fcntl.ioctl (s.fileno (), 0x8915, struct.pack ('256s', 'enp0s31f6' [: 15] .encode ('utf-8') )) [20:24]) '192.168.1.1'
cessatore

12

Variazione sulla risposta di ninjagecko. Questo dovrebbe funzionare su qualsiasi LAN che consenta la trasmissione UDP e non richieda l'accesso a un indirizzo su LAN o Internet.

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())

Aspetta, come è <broadcast>un nome host valido? !! Quanti di questi tipi di nomi host verbali sono validi?
Dev Aggarwal,

Questo funziona per me su Ubuntu 20.04 - ottenere 192.168.0.24 non 127.0.0.1
Lewis Morris l'

8

Temo che non ci siano buoni modi indipendenti dalla piattaforma per farlo oltre a collegarsi a un altro computer e farti inviare il tuo indirizzo IP. Ad esempio: findmyipaddress . Nota che questo non funzionerà se hai bisogno di un indirizzo IP dietro NAT a meno che anche il computer a cui ti stai connettendo sia dietro NAT.

Ecco una soluzione che funziona in Linux: ottenere l'indirizzo IP associato a un'interfaccia di rete .


8

Un modo semplice per produrre output "puliti" tramite utils a riga di comando:

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

Mostrerà tutti gli indirizzi IPv4 sul sistema.


1
Non mostrerà tutti gli indirizzi IPv4, perché ifconfig ti dice solo quelli primari. Devi usare "ip" da iproute2 per vedere tutti gli indirizzi.
Helmut Grohne,

È una gran quantità di shell per una domanda che richiede la libreria standard ... Inoltre, l'analisi di ifconfig non è portatile e non funzionerà in modo affidabile su una macchina.
Dominik George,

7

Cordiali saluti, posso verificare che il metodo:

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

Funziona su OS X (10.6, 10.5), Windows XP e su un server dipartimentale RHEL ben amministrato. Non ha funzionato su una VM CentOS minimale su cui eseguo solo un po 'di hacking del kernel. Quindi per quell'istanza puoi semplicemente controllare un indirizzo 127.0.0.1 e in quel caso fare quanto segue:

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

E quindi analizzare l'indirizzo IP dall'output. Va notato che per impostazione predefinita ifconfig non si trova nel PERCORSO di un normale utente ed è per questo che do il percorso completo nel comando. Spero che questo possa essere d'aiuto.


7

Questa è una variante della risposta di UnkwnTech: fornisce una get_local_addr()funzione che restituisce l'indirizzo IP LAN primario dell'host. Lo sto pubblicando perché questo aggiunge una serie di cose: supporto ipv6, gestione degli errori, ignorando gli host localhost / linklocal e usa un addr TESTNET (rfc5737) per connettersi.

# 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

Ho pensato che potesse essere una risposta davvero buona ... ma torna sempreNone
Jamie Lindsey il

@JamieLindsey Hai qualche dettaglio sul tuo sistema operativo, sulla configurazione della rete? Inoltre, cosa get_local_addr(remove="www.google.com")restituisce qualcosa di simile ? La registrazione dei dati socket.errorgenerati da _get_local_addr () potrebbe aiutare in modo diagnostico.
Eli Collins,

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

1
Hmm ... su un server con due NIC questo fornisce uno degli indirizzi IP assegnati, ma ripetuto tre volte. Sul mio laptop dà "127.0.1.1" (ripetuto tre volte ...) ...
bryn

Mi dà ['fe80::34e8:fe19:1459:2cde%22','fe80::d528:99fb:d572:e289%12', '192.168.56.1', '192.168.1.2']sul desktop di Windows.
Nakilon,

5

Questo funzionerà sulla maggior parte dei box Linux:

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

Questa risposta è il mio tentativo personale di risolvere il problema di ottenere l'IP LAN, poiché ha socket.gethostbyname(socket.gethostname())anche restituito 127.0.0.1. Questo metodo non richiede Internet solo una connessione LAN. Il codice è per Python 3.x ma potrebbe essere facilmente convertito per 2.x. Utilizzando 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
Cosa succede se lo esegui contemporaneamente su due macchine sulla stessa rete? Durante la trasmissione del messaggio sulla rete, tutte le macchine riceveranno "Qual è il mio indirizzo IP LAN. Il tuo udp_listening_server potrebbe rispondere "il tuo indirizzo IP è xxx" al messaggio.
Nicolas Defranoux,

4

127.0.1.1 è il tuo vero indirizzo IP. Più in generale, un computer può avere un numero qualsiasi di indirizzi IP. Puoi filtrarli per reti private: 127.0.0.0/8, 10.0.0.0/8, 172.16.0.0/12 e 192.168.0.0/16.

Tuttavia, non esiste un modo multipiattaforma per ottenere tutti gli indirizzi IP. Su Linux, puoi usare SIOCGIFCONFioctl.


2
Intende il suo IP visibile esternamente. L'intervallo 127. *. *. * Si riferisce in genere a localhost o una rete interna, che chiaramente non è quello che vuole.
Cerin,

4

Un leggero perfezionamento della versione dei comandi che utilizza il comando IP e restituisce gli indirizzi IPv4 e IPv6:

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

Bene, puoi usare il comando "ip route" su GNU / Linux per conoscere il tuo attuale indirizzo IP.

Questo mostra l'IP fornito all'interfaccia dal server DHCP in esecuzione sul router / modem. Di solito "192.168.1.1/24" è l'IP per la rete locale dove "24" indica l'intervallo di indirizzi IP possibili indicato dal server DHCP all'interno dell'intervallo di maschere.

Ecco un esempio: nota che PyNotify è solo un'aggiunta per chiarire il mio punto di vista e non è richiesto affatto

#! /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()    

Il vantaggio è che non è necessario specificare l'interfaccia di rete. È piuttosto utile quando si esegue un server socket

Puoi installare PyNotify usando easy_install o anche Pip:

easy_install py-notify

o

pip install py-notify

o all'interno di script / interprete python

from pip import main

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

4

Se stai cercando un indirizzo IPV4 diverso dal tuo indirizzo IP localhost 127.0.0.1, ecco un bel pezzo di codici Python:

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

Che può anche essere scritto in una sola riga:

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

Anche se si mette localhostin /etc/hostname, il codice sarà ancora dare il vostro indirizzo IP locale.


4

Per Linux, puoi semplicemente usare check_outputil hostname -Icomando di sistema in questo modo:

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

per i googler, so che la domanda era per una soluzione multipiattaforma
Kasper Skytte Andersen,

3

Nota: questo non utilizza la libreria standard, ma piuttosto semplice.

$ pip install pif

from pif import get_public_ip
get_public_ip()

3
le domande riguardavano la ricerca dell'IP usando stdlib
Alexandru Chirila,

3

netifaces è disponibile tramite pip e easy_install. (Lo so, non è nella base, ma potrebbe valere la pena l'installazione.)

netifaces ha delle stranezze tra le piattaforme:

  • L'interfaccia localhost / loop-back potrebbe non essere sempre inclusa (Cygwin).
  • Gli indirizzi sono elencati per protocollo (ad es. IPv4, IPv6) e i protocolli sono elencati per interfaccia. Su alcuni sistemi (Linux) ogni coppia protocollo-interfaccia ha la sua interfaccia associata (usando il nome interfaccia: notazione n) mentre su altri sistemi (Windows) una singola interfaccia avrà un elenco di indirizzi per ciascun protocollo. In entrambi i casi esiste un elenco di protocolli, ma può contenere solo un singolo elemento.

Ecco alcuni codici netifaces con cui giocare:

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.

Il codice sopra riportato non associa un indirizzo al nome della sua interfaccia (utile per generare regole ebtables / iptables al volo). Quindi ecco una versione che mantiene le informazioni sopra con il nome dell'interfaccia in una tupla:

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]

E, no, non sono innamorato della comprensione dell'elenco. In questi giorni è solo il modo in cui funziona il mio cervello.

Il frammento seguente stamperà tutto:

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)

Godere!


netifaces semplifica molto la vita affrontando questo problema.
Drake Guan,

3

Una versione Python 3.4 che utilizza il pacchetto asyncio appena introdotto.

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

Questo si basa sulla risposta eccellente di UnkwnTech .


3

Per ottenere l'indirizzo IP puoi usare un comando shell direttamente in Python :

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()
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.