如何找到本地IP地址(即192.168.x。x或10.0.x.x)在Python平台独立,只使用标准库?
当前回答
对于linux,你可以使用hostname -I system命令的check_output,就像这样:
from subprocess import check_output
check_output(['hostname', '-I'])
其他回答
你可以使用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上工作。
恐怕除了连接到另一台计算机并让它把你的IP地址发送给你之外,没有任何好的独立于平台的方法来做到这一点。例如:findmyipaddress。注意,如果你需要一个NAT后的IP地址,除非你所连接的计算机也是NAT后的IP地址,这是行不通的。
下面是一个适用于Linux的解决方案:获取与网络接口关联的IP地址。
一台计算机可以有多个网络接口(包括您提到的本地环回127.0.0.1)。就操作系统而言,它也是一个“真实IP地址”。
如果你想跟踪所有的接口,看看下面的Python包,参见:http://alastairs-place.net/netifaces/
我认为,如果您从主机文件中删除环回条目,就可以避免gethostbyname返回127.0.0.1。(有待核实)。
[仅限Windows]如果您不想使用外部包,也不想依赖外部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上工作。
在拥有iproute2实用程序的现代*NIX系统上,您可以通过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