[英]How can I get the IP address from a NIC (network interface controller) in Python?
When an error occurs in a Python script on Unix, an email is sent.当 Unix 上的 Python 脚本发生错误时,将发送 email。
I have been asked to add {Testing Environment} to the subject line of the email if the IP address is 192.168.100.37 which is the testing server.如果 IP 地址是测试服务器 192.168.100.37,我被要求将 {Testing Environment} 添加到 email 的主题行。 This way we can have one version of a script and a way to tell if the email is coming from messed up data on the testing server.这样我们就可以拥有一个脚本版本和一种方法来判断 email 是否来自测试服务器上的混乱数据。
However, when I google I keep finding this code:然而,当我用谷歌搜索时,我一直在寻找这段代码:
import socket
socket.gethostbyname(socket.gethostname())
However, that's giving me the IP address of 127.0.1.1.但是,这给了我 127.0.1.1 的 IP 地址。 When I use ifconfig
I get this当我使用ifconfig
我得到这个
eth0 Link encap:Ethernet HWaddr 00:1c:c4:2c:c8:3e
inet addr:192.168.100.37 Bcast:192.168.100.255 Mask:255.255.255.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:75760697 errors:0 dropped:411180 overruns:0 frame:0
TX packets:23166399 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:59525958247 (59.5 GB) TX bytes:10142130096 (10.1 GB)
Interrupt:19 Memory:f0500000-f0520000
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
UP LOOPBACK RUNNING MTU:16436 Metric:1
RX packets:25573544 errors:0 dropped:0 overruns:0 frame:0
TX packets:25573544 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:44531490070 (44.5 GB) TX bytes:44531490070 (44.5 GB)
Firstly, I don't know where it got 127.0.1.1 from, but either way that's not what I want.首先,我不知道它从哪里得到 127.0.1.1,但无论哪种方式,这都不是我想要的。 When I google I keep coming to the same syntax, Bash scripts or netifaces and I'm trying to use standard libraries.当我用谷歌搜索时,我一直使用相同的语法, Bash脚本或 netifaces,我正在尝试使用标准库。
So how can I get the IP address of eth0 in Python?那么如何获取Python中eth0的IP地址呢?
Two methods:两种方法:
You need to ask for the IP address that is bound to your eth0
interface.您需要询问绑定到eth0
接口的 IP 地址。 This is available from the netifaces package这可以从netifaces 包中获得
import netifaces as ni
ni.ifaddresses('eth0')
ip = ni.ifaddresses('eth0')[ni.AF_INET][0]['addr']
print(ip) # should print "192.168.100.37"
You can also get a list of all available interfaces via您还可以通过以下方式获取所有可用接口的列表
ni.interfaces()
Here's a way to get the IP address without using a python package:这是一种无需使用python包即可获取IP地址的方法:
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') # '192.168.0.110'
Note: detecting the IP address to determine what environment you are using is quite a hack.注意:通过检测 IP 地址来确定您正在使用的环境是一个非常棘手的问题。 Almost all frameworks provide a very simple way to set/modify an environment variable to indicate the current environment.几乎所有框架都提供了一种非常简单的方法来设置/修改环境变量以指示当前环境。 Try and take a look at your documentation for this.尝试查看您的文档。 It should be as simple as doing它应该像做一样简单
if app.config['ENV'] == 'production':
#send production email
else:
#send development email
Alternatively, if you want to get the IP address of whichever interface is used to connect to the network without having to know its name, you can use this:或者,如果您想获取用于连接到网络的任何接口的 IP 地址而不必知道其名称,您可以使用以下命令:
import socket
def get_ip_address():
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.connect(("8.8.8.8", 80))
return s.getsockname()[0]
I know it's a little different than your question, but others may arrive here and find this one more useful.我知道这与您的问题略有不同,但其他人可能会到达这里并发现这个问题更有用。 You do not have to have a route to 8.8.8.8 to use this.您不必有到 8.8.8.8 的路由来使用它。 All it is doing is opening a socket, but not sending any data.它所做的只是打开一个套接字,但不发送任何数据。
Since most of the answers use ifconfig
to extract the IPv4 from the eth0 interface, which is deprecated in favor of ip addr
, the following code could be used instead:由于大多数答案使用ifconfig
从 eth0 接口提取 IPv4,该接口已被弃用而支持ip addr
,因此可以使用以下代码:
import os
ipv4 = os.popen('ip addr show eth0 | grep "\<inet\>" | awk \'{ print $2 }\' | awk -F "/" \'{ print $1 }\'').read().strip()
ipv6 = os.popen('ip addr show eth0 | grep "\<inet6\>" | awk \'{ print $2 }\' | awk -F "/" \'{ print $1 }\'').read().strip()
Alternatively, you can shift part of the parsing task to the python interpreter by using split()
instead of grep and awk, as @serg points out in the comment:或者,您可以使用split()
而不是 grep 和 awk 将部分解析任务转移到 python 解释器,正如@serg 在评论中指出的那样:
import os
ipv4 = os.popen('ip addr show eth0').read().split("inet ")[1].split("/")[0]
ipv6 = os.popen('ip addr show eth0').read().split("inet6 ")[1].split("/")[0]
But in this case you have to check the bounds of the array returned by each split()
call.但是在这种情况下,您必须检查每个split()
调用返回的数组的边界。
Another version using regex:使用正则表达式的另一个版本:
import os
import re
ipv4 = re.search(re.compile(r'(?<=inet )(.*)(?=\/)', re.M), os.popen('ip addr show eth0').read()).groups()[0]
ipv6 = re.search(re.compile(r'(?<=inet6 )(.*)(?=\/)', re.M), os.popen('ip addr show eth0').read()).groups()[0]
If you only need to work on Unix, you can use a system call (ref. Stack Overflow question Parse ifconfig to get only my IP address using Bash ):如果您只需要在 Unix 上工作,您可以使用系统调用(参考 Stack Overflow question Parse ifconfig to get only my IP address using Bash ):
import os
f = os.popen('ifconfig eth0 | grep "inet\ addr" | cut -d: -f2 | cut -d" " -f1')
your_ip=f.read()
Building on the answer from @jeremyjjbrown, another version that cleans up after itself as mentioned in the comments to his answer.以@jeremyjjbrown 的答案为基础,这是另一个版本,如对他的答案的评论中所述,会自行清理。 This version also allows providing a different server address for use on private internal networks, etc..此版本还允许提供不同的服务器地址以用于私有内部网络等。
import socket
def get_my_ip_address(remote_server="google.com"):
"""
Return the/a network-facing IP number for this system.
"""
with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as s:
s.connect((remote_server, 80))
return s.getsockname()[0]
try below code, it works for me in Mac10.10.2:试试下面的代码,它在 Mac10.10.2 中对我有用:
import subprocess
if __name__ == "__main__":
result = subprocess.check_output('ifconfig en0 |grep -w inet', shell=True) # you may need to use eth0 instead of en0 here!!!
print 'output = %s' % result.strip()
# result = None
ip = ''
if result:
strs = result.split('\n')
for line in strs:
# remove \t, space...
line = line.strip()
if line.startswith('inet '):
a = line.find(' ')
ipStart = a+1
ipEnd = line.find(' ', ipStart)
if a != -1 and ipEnd != -1:
ip = line[ipStart:ipEnd]
break
print 'ip = %s' % ip
Yet another way of obtaining the IP Address from a NIC, using Python.使用 Python 从 NIC 获取 IP 地址的另一种方法。
I had this as part of an app that I developed long time ago, and I didn't wanted to simply git rm script.py
.我把它作为我很久以前开发的应用程序的一部分,我不想简单地git rm script.py
。 So, here I provide the approach, using subprocess
and list comprehensions for the sake of functional approach and less lines of code:所以,在这里我提供了一种方法,为了功能方法和更少的代码行,使用subprocess
和列表subprocess
:
import subprocess as sp
__version__ = "v1.0"
__author__ = "@ivanleoncz"
def get_nic_ipv4(nic):
"""
Get IP address from a NIC.
Parameter
---------
nic : str
Network Interface Card used for the query.
Returns
-------
ipaddr : str
Ipaddress from the NIC provided as parameter.
"""
result = None
try:
result = sp.check_output(["ip", "-4", "addr", "show", nic],
stderr=sp.STDOUT)
except Exception:
return "Unkown NIC: %s" % nic
result = result.decode().splitlines()
ipaddr = [l.split()[1].split('/')[0] for l in result if "inet" in l]
return ipaddr[0]
Additionally, you can use a similar approach for obtaining a list of NICs:此外,您可以使用类似的方法来获取 NIC 列表:
def get_nics():
"""
Get all NICs from the Operating System.
Returns
-------
nics : list
All Network Interface Cards.
"""
result = sp.check_output(["ip", "addr", "show"])
result = result.decode().splitlines()
nics = [l.split()[1].strip(':') for l in result if l[0].isdigit()]
return nics
Here's the solution as a Gist .这是作为Gist的解决方案。
And you would have something like this:你会有这样的事情:
$ python3
Python 3.6.7 (default, Oct 22 2018, 11:32:17)
[GCC 8.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>
>>>
>>> import helpers
>>>
>>> helpers.get_nics()
['lo', 'enp1s0', 'wlp2s0', 'docker0']
>>> helpers.get_nic_ipv4('docker0')
'172.17.0.1'
>>> helpers.get_nic_ipv4('docker2')
'Unkown NIC: docker2'
This will gather all IPs on the host and filter out loopback/link-local and IPv6.这将收集主机上的所有 IP 并过滤掉环回/本地链路和 IPv6。 This can also be edited to allow for IPv6 only, or both IPv4 and IPv6, as well as allowing loopback/link-local in IP list.这也可以编辑为仅允许 IPv6,或同时允许 IPv4 和 IPv6,以及允许 IP 列表中的环回/链路本地。
from socket import getaddrinfo, gethostname
import ipaddress
def get_ip(ip_addr_proto="ipv4", ignore_local_ips=True):
# By default, this method only returns non-local IPv4 Addresses
# To return IPv6 only, call get_ip('ipv6')
# To return both IPv4 and IPv6, call get_ip('both')
# To return local IPs, call get_ip(None, False)
# Can combime options like so get_ip('both', False)
af_inet = 2
if ip_addr_proto == "ipv6":
af_inet = 30
elif ip_addr_proto == "both":
af_inet = 0
system_ip_list = getaddrinfo(gethostname(), None, af_inet, 1, 0)
ip_list = []
for ip in system_ip_list:
ip = ip[4][0]
try:
ipaddress.ip_address(str(ip))
ip_address_valid = True
except ValueError:
ip_address_valid = False
else:
if ipaddress.ip_address(ip).is_loopback and ignore_local_ips or ipaddress.ip_address(ip).is_link_local and ignore_local_ips:
pass
elif ip_address_valid:
ip_list.append(ip)
return ip_list
print(f"Your IP Address is: {get_ip()}")
Returns Your IP Address is: ['192.168.1.118']返回您的 IP 地址是:['192.168.1.118']
If I run get_ip('both', False), it returns如果我运行 get_ip('both', False),它返回
Your IP Address is: ['::1', 'fe80::1', '127.0.0.1', '192.168.1.118', 'fe80::cb9:d2dd:a505:423a']您的 IP 地址是:['::1', 'fe80::1', '127.0.0.1', '192.168.1.118', 'fe80::cb9:d2dd:a505:423a']
It worked for me它对我有用
import subprocess
my_ip = subprocess.Popen(['ifconfig eth0 | awk "/inet /" | cut -d":" -f 2 | cut -d" " -f1'], stdout=subprocess.PIPE, shell=True)
(IP,errors) = my_ip.communicate()
my_ip.stdout.close()
print IP
Find the IP address of the first eth/wlan entry in ifconfig that's RUNNING:在正在运行的 ifconfig 中找到第一个 eth/wlan 条目的 IP 地址:
import itertools
import os
import re
def get_ip():
f = os.popen('ifconfig')
for iface in [' '.join(i) for i in iter(lambda: list(itertools.takewhile(lambda l: not l.isspace(),f)), [])]:
if re.findall('^(eth|wlan)[0-9]',iface) and re.findall('RUNNING',iface):
ip = re.findall('(?<=inet\saddr:)[0-9\.]+',iface)
if ip:
return ip[0]
return False
This is the result of ifconfig:这是 ifconfig 的结果:
pi@raspberrypi:~ $ ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.2.24 netmask 255.255.255.0 broadcast 192.168.2.255
inet6 fe80::88e9:4d2:c057:2d5f prefixlen 64 scopeid 0x20<link>
ether b8:27:eb:d0:9a:f3 txqueuelen 1000 (Ethernet)
RX packets 261861 bytes 250818555 (239.1 MiB)
RX errors 0 dropped 6 overruns 0 frame 0
TX packets 299436 bytes 280053853 (267.0 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10<host>
loop txqueuelen 1000 (Local Loopback)
RX packets 74 bytes 16073 (15.6 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 74 bytes 16073 (15.6 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
wlan0: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500
ether b8:27:eb:85:cf:a6 txqueuelen 1000 (Ethernet)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
pi@raspberrypi:~ $
Cutting a bit the output, we have:减少一点输出,我们有:
pi@raspberrypi:~ $
pi@raspberrypi:~ $ ifconfig eth0 | grep "inet 192" | cut -c 14-25
192.168.2.24
pi@raspberrypi:~ $
pi@raspberrypi:~ $
Now, we can go to python and do:现在,我们可以转到 python 并执行以下操作:
import os
mine = os.popen('ifconfig eth0 | grep "inet 192" | cut -c 14-25')
myip = mine.read()
print (myip)
If you want to do it the hard (but maybe fast?) way, here's some rough netlink (rfc3549) code (probably linux only) which gets both ipv4 and ipv6, with just one import statement from the standard library:如果你想用硬(但可能很快?)的方式来做,这里有一些粗略的 netlink (rfc3549) 代码(可能仅限于 linux),它同时获取 ipv4 和 ipv6,只有一个来自标准库的导入语句:
import socket
# https://www.man7.org/linux/man-pages/man7/rtnetlink.7.html
# https://github.com/torvalds/linux/blob/master/include/uapi/linux/rtnetlink.h
RTM_NEWADDR = 20
RTM_GETADDR = 22
# https://www.man7.org/linux/man-pages/man7/netlink.7.html
# https://github.com/torvalds/linux/blob/master/include/uapi/linux/netlink.h
NLM_F_REQUEST = 0x01
NLM_F_ROOT = 0x100
s = socket.socket(socket.AF_NETLINK, socket.SOCK_RAW)
req = (
# nlmsghdr
int.to_bytes(0, 4, 'little', signed=False) + # nlmsg_len
int.to_bytes(RTM_GETADDR, 2, 'little', signed=False) + # nlmsg_type
int.to_bytes(NLM_F_REQUEST | NLM_F_ROOT, 2, 'little', signed=False) + # nlmsg_flags
int.to_bytes(0, 2, 'little', signed=False) + # nlmsg_seq
int.to_bytes(0, 2, 'little', signed=False) + # nlmsg_pid
# ifinfomsg
b'\0' * 8
)
req = int.to_bytes(len(req), 4, 'little') + req[4:]
s.sendall(req)
full_resp = s.recv(4096)
while full_resp:
resp = full_resp
# nlmsghdr
nlmsg_len = int.from_bytes(resp[0:4], 'little', signed=False)
nlmsg_type = int.from_bytes(resp[4:6], 'little', signed=False)
assert not nlmsg_len % 4, nlmsg_len
resp = resp[16:nlmsg_len]
full_resp = full_resp[nlmsg_len:]
if nlmsg_type == 3: # NLMSG_DONE
assert not full_resp, full_resp
break
if not full_resp:
full_resp = s.recv(4096)
assert nlmsg_type == RTM_NEWADDR, (nlmsg_type, resp[:32])
# ifaddrmsg
ifa_family = int.from_bytes(resp[0:1], 'little', signed=False)
ifa_index = int.from_bytes(resp[4:8], 'little', signed=False)
resp = resp[8:]
while resp:
# rtattr
rta_len = int.from_bytes(resp[0:2], 'little', signed=False)
rta_type = int.from_bytes(resp[2:4], 'little', signed=False)
data = resp[4:rta_len]
if rta_type == 1: # IFLA_ADDRESS
if ifa_family == socket.AF_INET:
ip = '.'.join('%d' % c for c in data)
if ifa_family == socket.AF_INET6:
ip = ':'.join(('%02x%02x' % (chunk[0], chunk[1]) if chunk != b'\0\0' else '') for chunk in [data[0:2], data[2:4], data[4:6], data[6:8], data[8:10], data[10:12], data[12:14], data[14:16]])
print('interface #%s has %s' % (ifa_index, ip))
if rta_type == 3: # IFLA_IFNAME
ifname = data.rstrip(b'\0').decode()
print('interface #%s is named %s' % (ifa_index, ifname))
# need to round up to multiple of 4
if rta_len % 4:
rta_len += 4 - rta_len % 4
resp = resp[rta_len:]
s.close()
If you just need ipv4, the oldschool SIOCGIFADDR
ioctl
method in another answer is probably more straightforward.如果您只需要 ipv4,另一个答案中的 oldschool SIOCGIFADDR
ioctl
方法可能更简单。 For ipv6, there's /proc/net/if_inet6
.对于 ipv6,有/proc/net/if_inet6
。
Answer using psutil :使用psutil回答:
import psutil
import socket
def get_ipv4_from_nic(interface):
interface_addrs = psutil.net_if_addrs().get(interface) or []
for snicaddr in interface_addrs:
if snicaddr.family == socket.AF_INET:
return snicaddr.addressinterface_addrs]
Example:例子:
>>> get_ipv4_from_nic("eth0")
'192.168.100.37'
try this:尝试这个:
import netifaces as ni将 netifaces 导入为 ni
def test_netowrk(): interfaces = ni.interfaces() def test_netowrk(): interfaces = ni.interfaces()
for i in interfaces: #will cycle through all available interfaces and check each one. you can use anything for "i". its almost like saying import netifaces as ni. but i doesn't need to be declared, the systems assumes that for (what you put here) in interfaces means what you put there should resemble each of the results returned are represented by i.
if i != "lo": #lo is the local loopback. This will remove lo from the interfaces it checks.
try:
ni.ifaddresses(i)
gws = ni.gateways()
gateway = gws['default'][ni.AF_INET][0]
ip = ni.ifaddresses(i)[ni.AF_INET][0]['addr']
sm = ni.ifaddresses(i)[ni.AF_INET][0]['netmask']
print ("Network information for " + i + ":")
print ("IP: " + ip)
print ("Subnet Mask: " + sm)
print ("Gateway: " + gateway)
print ()
except: #this is good to have in case you have a disconnected wifi or trying to test a network with no DHCP
print (i + " is not connected or DHCP is not available. Try setting a static IP.")
test_netowrk()测试网络()
results:结果:
Network information for eth0: eth0 的网络信息:
IP: 192.168.1.172 IP:192.168.1.172
Subnet Mask: 255.255.255.0子网掩码:255.255.255.0
Gateway: 192.168.1.254网关:192.168.1.254
wlan0 is not connected or DHCP is not available. wlan0 未连接或 DHCP 不可用。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.