如何在Python中获取eth0的IP地址?

时间:2014-06-13 02:46:11

标签: python unix

当Unix上的Python脚本发生错误时,会发送一封电子邮件。

如果IP地址是测试服务器的192.168.100.37,我被要求将{Testing Environment}添加到电子邮件的主题行。通过这种方式,我们可以拥有一个版本的脚本,以及一种判断电子邮件是否来自测试服务器上的混乱数据的方法。

然而,当我谷歌时,我一直在寻找这段代码:

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

然而,这给了我IP地址127.0.1.1。当我使用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)

首先,我不知道它从哪里得到127.0.1.1,但不管怎么说都不是我想要的。当我谷歌时,我不断使用相同的语法,Bash脚本或netifaces,我正在尝试使用标准库。

那么如何在Python中获取eth0的IP地址呢?

13 个答案:

答案 0 :(得分:147)

两种方法:

方法#1(使用外部包)

您需要询问绑定到eth0接口的IP地址。这可以从netifaces package

获得
import netifaces as ni
ni.ifaddresses('eth0')
ip = ni.ifaddresses('eth0')[ni.AF_INET][0]['addr']
print ip  # should print "192.168.100.37"

您还可以通过

获取所有可用接口的列表
ni.interfaces()

方法#2(无外部包装)

这是一种在不使用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'

注意:检测IP地址以确定您正在使用的环境非常糟糕。几乎所有框架都提供了一种非常简单的方法来设置/修改环境变量以指示当前环境。请尝试查看您的文档。它应该像做

一样简单
if app.config['ENV'] == 'production':
  #send production email
else:
  #send development email

答案 1 :(得分:96)

或者,如果您想获取用于连接到网络的任何接口的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]

我知道这与你的问题有点不同,但其他人可能会到达这里并发现这个更有用。您没有必要使用8.8.8.8的路由来使用它。它所做的就是打开一个套接字,但不发送任何数据。

答案 2 :(得分:25)

为接口返回带有ip-addresses的字符串的简单方法是:

from subprocess import check_output

ips = check_output(['hostname', '--all-ip-addresses'])

有关详细信息,请参阅hostname

答案 3 :(得分:16)

如果您只需要在Unix上工作,则可以使用系统调用(参见Stack Overflow问题 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()

答案 4 :(得分:15)

由于大多数答案使用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()

更新:

或者,您可以使用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]

但在这种情况下,您必须检查每个split()调用返回的数组的边界。

更新2:

使用正则表达式的另一个版本:

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]

答案 5 :(得分: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

答案 6 :(得分:1)

以@jeremyjjbrown的答案为基础,另一个版本会根据其答案的注释中提到的内容自行清理。此版本还允许提供其他服务器地址,以供在专用内部网络等上使用。

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]

答案 7 :(得分:0)

它对我有用

contourSizes()

答案 8 :(得分:0)

在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

答案 9 :(得分:0)

这是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:~ $ 

剪切一点输出,我们有:

pi@raspberrypi:~ $ 
pi@raspberrypi:~ $ ifconfig eth0 | grep "inet 192" | cut -c 14-25
192.168.2.24
pi@raspberrypi:~ $ 
pi@raspberrypi:~ $ 

现在,我们可以转到python并执行以下操作:

import os
mine = os.popen('ifconfig eth0 | grep "inet 192" | cut -c 14-25')
myip = mine.read()
print (myip)

答案 10 :(得分:0)

还有另一种使用Python从NIC获取IP地址的方法。

我把它作为我很久以前开发的应用程序的一部分,我不想简单地git rm script.py。因此,在这里,我提供了使用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]

此外,您可以使用类似的方法来获取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                                                

这是Gist的解决方案。

您将遇到类似这样的内容:

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

答案 11 :(得分:0)

这将收集主机上的所有IP,并过滤掉环回/本地链接和IPv6。还可以对其进行编辑,以仅允许使用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()}")

返回您的IP地址为:['192.168.1.118']

如果我运行get_ip('both',False),它将返回

您的IP地址为:[':: 1','fe80 :: 1','127.0.0.1','192.168.1.118','fe80 :: cb9:d2dd:a505:423a']

答案 12 :(得分:-1)

试试这个:

将 netifaces 导入为 ni

def test_netowrk(): 接口 = 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()

结果:

eth0 的网络信息:

IP:192.168.1.172

子网掩码:255.255.255.0

网关:192.168.1.254

wlan0 未连接或 DHCP 不可用。