使用Python's stdlib查找本地IP地址

如何找到本地IP地址(即192.168.x。x或10.0.x.x)在Python平台独立,只使用标准库?

904718 次浏览
import socket
socket.gethostbyname(socket.gethostname())

这并不总是有效(在主机名/etc/hosts127.0.0.1的机器上返回127.0.0.1), gimel显示的是缓和,使用socket.getfqdn()代替。当然,您的机器需要一个可解析的主机名。

恐怕除了连接到另一台计算机并让它把你的IP地址发送给你之外,没有任何好的独立于平台的方法来做到这一点。例如:findmyipaddress。注意,如果你需要一个NAT后的IP地址,除非你所连接的计算机也是NAT后的IP地址,这是行不通的。

下面是一个适用于Linux的解决方案:获取与网络接口关联的IP地址

我刚发现这个,但它似乎有点hack,然而他们说尝试它在*nix和我在windows上,它工作。

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

这假设您有internet访问,并且没有本地代理。

您可以使用netifaces模块。类型:

pip install netifaces

在你的命令shell中,它会在默认的Python安装中安装自己。

然后你可以这样使用它:

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

在我的电脑上,它打印出:

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

这个模块的作者声称它应该在Windows、UNIX和Mac OS X上工作。

如果您不想使用外部包,也不想依赖外部Internet服务器,这可能会有所帮助。这是我在谷歌代码搜索上找到的一个代码示例,并修改以返回所需的信息:

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

用法:

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

由于它依赖于windll,这将只在Windows上工作。

作为别名myip:

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])'"
  • 适用于Python 2。3. Python。x,现代和旧的Linux发行版,OSX/macOS和Windows来查找当前的IPv4地址。
  • 对于有多个IP地址、IPv6、没有配置IP地址或没有互联网访问的机器,将不会返回正确的结果。
  • 据报道,这在最新版本的macOS上不起作用。

请注意:如果你打算在Python程序中使用这样的东西,正确的方法是使用支持IPv6的Python模块。


与上面相同,但只是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])
  • 如果没有配置IP地址,将抛出异常。

也可以在没有互联网连接的局域网上工作的版本:

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

(由于# EYZ0)


# EYZ0:

使用socket.gethostbyname(socket.gethostname())在这里不起作用,因为我所在的一台计算机有一个/etc/hosts,其中有重复的条目和对自身的引用。socket.gethostbyname()只返回/etc/hosts中的最后一项。

这是我最初的尝试,它清除了所有以"127."开头的地址:

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

这适用于Python 2和3,在Linux和Windows上,但不能处理多个网络设备或IPv6。然而,它在最近的Linux发行版上停止工作,所以我尝试了这种替代技术。它试图连接到谷歌DNS服务器在8.8.8.8端口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])

然后,我将上述两种技术组合成一个应该在任何地方都适用的一行程序,并在这个答案的顶部创建了myip别名和Python代码片段。

随着IPv6的日益普及,对于具有多个网络接口的服务器,使用第三方Python模块查找IP地址可能比这里列出的任何方法都更健壮和可靠。

我使用以下模块:

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

测试了windows和linux(不需要额外的模块) 用于单个基于IPv4的LAN中的系统 接口名称的固定列表不适用于最近的linux版本,这些版本已经采用了systemd v197关于可预测接口名称的更改,如亚历山大所指出的。 在这种情况下,您需要手动将列表替换为系统上的接口名称,或使用其他解决方案,如netifaces.

供您参考,我可以验证该方法:

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

适用于OS X (10.6,10.5), Windows XP和管理良好的RHEL部门服务器。它不能在一个非常小的CentOS虚拟机上工作,我只是做了一些内核黑客。因此,对于该实例,您可以检查127.0.0.1地址,在这种情况下,执行以下操作:

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

然后从输出中解析ip地址。应该注意的是,默认情况下ifconfig不在普通用户的PATH中,这就是为什么我在命令中给出完整的路径。我希望这能有所帮助。

我在我的ubuntu机器上使用这个:

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

这行不通。

对于*nix系统上的IP地址列表,

import subprocess
co = subprocess.Popen(['ifconfig'], stdout = subprocess.PIPE)
ifconfig = co.stdout.read()
ip_regex = re.compile('((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-4]|2[0-5][0-9]|[01]?[0-9][0-9]?))')
[match[0] for match in ip_regex.findall(ifconfig, re.MULTILINE)]

虽然现在回答这个问题有点晚了,但我认为其他人可能会发现它有用:-)

PS:它会返回广播地址和网络掩码。

通过命令行utils产生“干净”输出的一个简单方法:

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

它将显示系统上的所有IPv4地址。

一台计算机可以有多个网络接口(包括您提到的本地环回127.0.0.1)。就操作系统而言,它也是一个“真实IP地址”。

如果你想跟踪所有的接口,看看下面的Puthon包:http://alastairs-place.net/netifaces/

我认为,如果您从主机文件中删除环回条目,就可以避免gethostbyname返回127.0.0.1。(有待核实)。

127.0.1.1 您的真实IP地址。更一般地说,一台计算机可以有任意数量的IP地址。您可以过滤它们为私有网络- 127.0.0.0/8,10.0.0.0/8,172.16.0.0/12和192.168.0.0/16。

但是,没有跨平台的方法来获取所有的IP地址。在Linux上,可以使用SIOCGIFCONF ioctl。

Socket API方法

看到# EYZ0

缺点:

  • 不是跨平台。
  • 需要更多的回退代码,与互联网上特定地址的存在相关联
  • 如果你在NAT后面,这也不能工作
  • 可能会创建一个UDP连接,而不是独立于(通常是ISP的)DNS可用性(参见其他答案,如使用8.8.8.8:谷歌的(巧合也是DNS)服务器)
  • 确保你的目标地址不可达,就像一个数字IP地址,是规格保证不使用。不要使用一些域名,如fakesubdomain.google.com或somefakewebsite.com;在这个过程中,您仍然会向该聚会发送垃圾邮件(现在或将来),以及发送您自己的网络盒子。

反射器方法

(请注意,这并没有回答OP的本地IP地址问题,例如192.168…;它会给你你的公共IP地址,根据用例,这可能更可取。)

你可以查询一些网站,如whatismyip.com(但有一个API),例如:

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)

或者如果使用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)

优点:

  • 这种方法的一个优点是它是跨平台的
  • 它从丑陋的nat(例如你的家用路由器)后面工作。

缺点(和变通方法):

  • 要求网站正常运行,格式不变(几乎肯定不会),DNS服务器正常工作。在失败的情况下,还可以通过查询其他第三方IP地址反射器来缓解这个问题。
  • 如果您不查询多个反射器(以防止一个受损害的反射器告诉您您的地址不是某个东西),或者如果您不使用HTTPS(以防止假装是服务器的中间人攻击),则可能的攻击向量

编辑:虽然最初我认为这些方法真的很糟糕(除非你使用了很多回退,否则这些代码在很多年之后可能就无关紧要了),但它确实提出了一个问题:“互联网是什么?”一台计算机可能有许多接口指向许多不同的网络。要更详细地描述这个主题,请使用gateways and routes的谷歌。计算机可以通过内部网关访问内部网络,或者通过路由器上的网关访问全球网络(通常是这种情况)。OP询问的本地IP地址仅针对单个链路层进行了定义,因此您必须指定它(“它是网卡,还是我们正在谈论的以太网电缆?”)。这个问题可能有多个非唯一的答案。然而,全球网络上的全球IP地址可能是定义良好的(在没有大规模网络碎片的情况下):可能是通过可以访问tld的网关的返回路径。

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

好吧,这是特定于Windows的,需要安装WMI模块,但这似乎比不断尝试调用外部服务器要少得多。这只是另一种选择,因为已经有很多好的选择,但它可能非常适合您的项目。

Import WMI


def getlocalip():
local = wmi.WMI()
for interface in local.Win32_NetworkAdapterConfiguration(IPEnabled=1):
for ip_address in interface.IPAddress:
if ip_address != '0.0.0.0':
localip = ip_address
return localip














>>>getlocalip()
u'xxx.xxx.xxx.xxx'
>>>

顺便说一下,WMI非常强大……如果你正在做任何窗口机器的远程管理,你一定要看看它能做什么。

我必须解决“判断一个IP地址是否是本地的”这个问题,我的第一个想法是建立一个本地IP列表,然后与之匹配。这让我想到了这个问题。然而,我后来意识到有一种更直接的方法:尝试绑定该IP,看看它是否有效。

_local_ip_cache = []
_nonlocal_ip_cache = []
def ip_islocal(ip):
if ip in _local_ip_cache:
return True
if ip in _nonlocal_ip_cache:
return False
s = socket.socket()
try:
try:
s.bind((ip, 0))
except socket.error, e:
if e.args[0] == errno.EADDRNOTAVAIL:
_nonlocal_ip_cache.append(ip)
return False
else:
raise
finally:
s.close()
_local_ip_cache.append(ip)
return True

我知道这并不能直接回答问题,但是这对于任何试图解决相关问题的人以及遵循相同思路的人都是有帮助的。我认为这是一个跨平台的解决方案。

这将在大多数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()

稍微改进了使用IP命令的命令版本,并返回IPv4和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)]
import socket
socket.gethostbyname(socket.getfqdn())

这个答案是我个人试图解决获得局域网IP的问题,因为socket.gethostbyname(socket.gethostname())也返回127.0.0.1。这种方法不需要Internet,只需要一个局域网连接。代码是为Python 3编写的。X但是可以很容易地转换为2.x。使用UDP广播:

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())
import socket
[i[4][0] for i in socket.getaddrinfo(socket.gethostname(), None)]

注意:这里没有使用标准库,但是非常简单。

$ PIP安装pif

from pif import get_public_ip
get_public_ip()

你可以在GNU/Linux上使用命令“ip route”来知道你当前的ip地址。

这显示了运行在路由器/调制解调器上的DHCP服务器给接口的IP地址。通常“192.168.1.1/24”是本地网络的IP地址,其中“24”是DHCP服务器在掩码范围内可能提供的IP地址范围。

这里有一个例子:请注意,PyNotify只是一个补充,以阐明我的观点,根本不是必需的

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

这样做的好处是您不需要指定网络接口。这在运行套接字服务器时非常有用

你可以使用easy_install甚至Pip安装PyNotify:

easy_install py-notify

pip install py-notify

或者在python脚本/解释器中

from pip import main


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

简单而甜蜜!

def getip():


import socket
hostname= socket.gethostname()
ip=socket.gethostbyname(hostname)


return(ip)

这是UnkwnTech的答案的一个变体——它提供了一个get_local_addr()函数,它返回主机的主LAN ip地址。我发布它是因为这增加了一些东西:ipv6支持,错误处理,忽略localhost/linklocal地址,并使用TESTNET地址(rfc5737)来连接。

# 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

ninjagecko回答的变体。这应该在任何允许UDP广播的LAN上工作,并且不需要访问LAN或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())

Netifaces可通过PIP和easy_install获得。(我知道,它不在基础,但它可能值得安装。)

Netifaces在不同平台上确实有一些奇怪之处:

  • localhost/loop-back接口可能并不总是包含在内(Cygwin)。
  • 地址按协议列出(例如IPv4, IPv6),协议按接口列出。在某些系统(Linux)上,每个协议-接口对都有自己的关联接口(使用interface_name:n表示法),而在其他系统(Windows)上,单个接口将有每个协议的地址列表。在这两种情况下都有一个协议列表,但它可能只包含一个元素。

下面是一些netifaces代码:

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.

上面的代码没有将地址映射回接口名(对于动态生成ebtables/iptables规则很有用)。所以这里有一个版本,它将上述信息和接口名称保存在一个元组中:

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]

而且,不,我不喜欢列表理解。这些天我的大脑就是这么运转的。

下面的代码段将全部打印出来:

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)

享受吧!

在Debian上(经过测试),我怀疑大多数Linux ..

import commands


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

在MS Windows上(已测试)

import socket


socket.gethostbyname(socket.gethostname())

如果计算机有到Internet的路由,即使/etc/hosts没有正确设置,总是也可以获得首选的本地ip地址。

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]
一个我不相信已经发布的版本。 我在Ubuntu 12.04上使用python 2.7进行测试

找到这个解决方案: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])

结果示例:

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

# EYZ0。

  • 不需要可路由的网络访问或任何连接。
  • 即使所有接口都从网络断开,也能正常工作。
  • 不需要甚至不尝试获得其他任何地方
  • 工作与NAT,公共,私有,外部和内部IP
  • 没有外部依赖的纯Python 2(或3)。
  • 支持Linux、Windows和OSX。

Python 3或2:

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

这将返回一个主IP(具有默认路由的IP)。如果您需要将所有IP附加到所有接口(包括本地主机等),请参阅类似这个答案的内容。

如果你在一个NAT防火墙后面,比如你家里的wifi路由器,那么这将不会显示你的公共NAT IP,而是显示你在本地网络上的私有IP,它有一个默认路由到你的本地wifi路由器。如果你需要外部IP:

  • 在该外部设备(wifi路由器)上运行此功能,或

  • 连接到外部服务,例如https://www.ipify.org/,可以反射从外部世界看到的IP

... 但这些想法与最初的问题完全不同。:)

这不是很Pythonic,但它在Windows上可靠地工作。

def getWinIP(version = 'IPv4'):
import subprocess
if version not in ['IPv4', 'IPv6']:
print 'error - protocol version must be "IPv4" or "IPv6"'
return None
ipconfig = subprocess.check_output('ipconfig')
my_ip = []
for line in ipconfig.split('\n'):
if 'Address' in line and version in line:
my_ip.append(line.split(' : ')[1].strip())
return my_ip


print getWinIP()

是的,这是一种黑客行为,但有时我不想事后怀疑操作系统,直接使用内置的和有效的操作系统就行了。

使用新引入的asyncio包的Python 3.4版本。

async def 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

这是基于UnkwnTech的优秀的答案

要获得ip地址,你可以直接在python中使用shell命令:

import socket, subprocess


def get_ip_and_hostname():
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 = get_ip_and_hostname()

我满足于使用ipfy: https://www.ipify.org的服务和/或API。

#!/usr/bin/env python3
from urllib.request import urlopen




def public_ip():
data = urlopen('https://api.ipify.org').read()
return str(data, encoding='utf-8')




print(public_ip())

响应也可以以JSONJSONP格式获得。

Github上有个ipify Python库

这与之前发布的答案非常相似,但我找不到任何与这种调用用法有关的答案。这是我用于ipv4的。对于ipv6,更改'。' in to ':' in

import socket
print next(i[4][0] for i in socket.getaddrinfo(
socket.gethostname(), 80) if '127.' not in i[4][0] and '.' in i[4][0]);"
from netifaces import interfaces, ifaddresses, AF_INET
iplist = [ifaddresses(face)[AF_INET][0]["addr"] for face in interfaces() if AF_INET in ifaddresses(face)]
print(iplist)
['10.8.0.2', '192.168.1.10', '127.0.0.1']
import socket
print(socket.gethostbyname(socket.getfqdn()))
import netifaces as ni


ni.ifaddresses('eth0')
ip = ni.ifaddresses('eth0')[ni.AF_INET][0]['addr']
print(ip)

这将返回你的IP地址在Ubuntu系统和MacOS。输出将是系统IP地址,如我的IP: 192.168.1.10。

如果你正在寻找与本地主机IP地址127.0.0.1不同的IPV4地址,这里有一段简洁的python代码:

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

也可以写成一行:

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

即使您将localhost放在/etc/hostname中,代码仍然会给出您的本地IP地址。

然而,前面答案的另一个变体,可以保存到一个名为my-ip-to的可执行脚本中:

#!/usr/bin/env python


import sys, socket


if len(sys.argv) > 1:
for remote_host in sys.argv[1:]:
# determine local host ip by outgoing test to another host
# use port 9 (discard protocol - RFC 863) over UDP4
with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as s:
s.connect((remote_host, 9))
my_ip = s.getsockname()[0]
print(my_ip, flush=True)
else:
import platform


my_name = platform.node()
my_ip = socket.gethostbyname(my_name)
print(my_ip)


它需要任意数量的远程主机,并打印出本地ip,逐个到达它们:

$ my-ip-to z.cn g.cn localhost
192.168.11.102
192.168.11.102
127.0.0.1
$

并在没有给出arg时打印best-bet。

$ my-ip-to
192.168.11.102

对于linux env,读取/proc/net/tcp,第二个(localaddress)和第三个(remoteaddress)将以六进制格式给出ip。

提示:如果第二列是零(00000000:000),那么它是一个监听端口:)

https://github.com/romol0s/python/blob/master/general/functions/getTcpListenIpsByPort.py

https://www.kernel.org/doc/Documentation/networking/proc_net_tcp.txt

对于linux,你可以像这样使用hostname -I系统命令中的check_output:

from subprocess import check_output
check_output(['hostname', '-I'])
pyroute2是一个很棒的库,不仅可以用来获取IP地址,还可以用来获取网关信息和其他有用的信息。 下面的代码可以获取任意接口的ipv4地址
from pyroute2 import IPRoute
ip = IPRoute()


def get_ipv4_address(intf):
return dict(ip.get_addr(label=intf)[0]['attrs'])['IFA_LOCAL']


print(get_ipv4_address('eth0'))

Windows解决方案,要么接受,要么放弃。

在当前活动的无线局域网[无线局域网]上,即计算机的ip地址(wifi路由器或网络交换机)。

注意:它不是设备的公共IP,不涉及任何外部请求、包和公共api。

核心思想是解析shell command: ipconfig或linux上的ifconfig的输出。我们使用子进程来获取输出。

def wlan_ip():
import subprocess
result=subprocess.run('ipconfig',stdout=subprocess.PIPE,text=True).stdout.lower()
scan=0
for i in result.split('\n'):
if 'wireless' in i: #use "wireless" or wireless adapters and "ethernet" for wired connections
scan=1
if scan:
if 'ipv4' in i:
return i.split(':')[1].strip()
print(wlan_ip())

这是在CMD:'ipconfig'后发生的事情:

我们得到这个输出,我们在python中使用subprocess output捕获它。

C:\Users\ dell> ipconfig

Wireless LAN adapter Wi-Fi:


Connection-specific DNS Suffix  . :
Link-local IPv6 Address . . . . . : fe80::f485:4a6a:e7d5:1b1c%4
IPv4 Address. . . . . . . . . . . : 192.168.0.131
Subnet Mask . . . . . . . . . . . : 255.255.255.0
Default Gateway . . . . . . . . . : 192.168.0.1

我们用python语言解析了字符串,以选择当前网络上无线适配器的IP的方式。

@fatal_error解决方案应该是接受的答案!这是他的解决方案在nodejs中的实现,以备人们需要:

const dgram = require('dgram');


async function get_local_ip() {
const s = new dgram.createSocket('udp4');
return new Promise((resolve, reject) => {
try {
s.connect(1, '8.8.8.8', function () {
const ip = s.address();
s.close();
resolve(ip.address)
});
} catch (e) {
console.error(e);
s.close();
reject(e);
}
})
}

你可以在现代*NIX系统上轻松地做到这一点,它有iproute2实用程序,通过subprocess.run()调用它,因为你可以用-j开关输出JSON,然后使用json.loads()模块和方法将其转换为python数据结构。下面的代码显示第一个非环回IP地址。

import subprocess
import json


ip = json.loads(subprocess.run('ip -j a'.split(),capture_output=True).stdout.decode())[1]['addr_info'][0]['local']


print(ip)

或者,如果你有多个IP,想要找到用于连接到特定目的地的IP,你可以使用ip -j route get 8.8.8.8,如下所示:

import subprocess
import json


ip = json.loads(subprocess.run('ip -j route get 8.8.8.8'.split(),capture_output=True).stdout.decode())[0]['prefsrc']


print(ip)

如果你寻找所有的IP地址,你可以遍历由ip -j a返回的字典列表

import subprocess
import json


list_of_dicts = json.loads(subprocess.run('ip -j a'.split(),capture_output=True).stdout.decode())


for interface in list_of_dicts:
try:print(f"Interface: {interface['ifname']:10} IP: {interface['addr_info'][0]['local']}")
except:pass