Python获取ip地址

1. 获取ip/MAC地址等

获取本地ip地址首先想到的命令是ifconfig,然后从结果中提取出ip地址,Python代码如下:

def get_ip():
    cmd = "/sbin/ifconfig | grep 'inet addr' | grep -v 127.0.0.1 | awk '{print $2}' | awk -F ':' '{print $2}'"
    pip = subprocess.Popen(cmd, shell = True, stdout = subprocess.PIPE)
    ip = pip.stdout.read()
    return ip

 
可能大家会觉得这样太山寨或者结果不太可信。而事实上,有一个包可以实现提取ip地址,它就是netifaces。netifaces官网地址是:https://pypi.python.org/pypi/netifaces/,里面有详细的介绍和示例。下面给出使用netifaces取得ip地址的代码: 

import netifaces
def get_current_ip():
    '''
    Using netifaces to fetch the ip address of the current machine.
    '''
    ips = []
    exclude_iface = ['lo']
    interfaces = netifaces.interfaces()
    for iface in interfaces:
        if iface not in exclude_iface:
            if netifaces.AF_INET in netifaces.ifaddresses(iface):
                addrs = netifaces.ifaddresses(iface)[netifaces.AF_INET] # mac addr: netifaces.AF_LINK
                for addr in addrs:
                    ips.append(info['addr'])
    return ips

ips = get_current_ip()
print ips

netifaces.ifaddresses(iface)返回一个字典,其中key为:18,2和30,分别代表协议:AF_LINK、AF_INET(IPV4)和AF_INET6 (IPv6)。上面代码中的addrs为一个列表(因为一台主机可以由多个ip地址),列表中的每个元素是一个字典,包含了广播地址(broadcast)、子网掩码(netmask)和IP地址(addr)。事实上netifaces除了可以查询上述信息,还可以查询物理地址(MAC地址或网卡地址)、网关(使用netifaces.gateways()),网关结果类似于:{'default': {2: ('192.168.1.1', 'eth0')}, 2: [('192.168.1.1', 'eth0', True)]},其中的key 2表示协议AF_INET(IPV4)。


2. 处理ip

取得ip地址后,若要对ip地址进行处理,则要用到subnets包,subnet官网教程,以下是摘取部分:

基本操作

In [1]: from netaddr import *

In [2]: import pprint

In [3]: ip = IPAddress("192.168.2.151")

In [4]: ip.version
Out[4]: 4

In [5]: repr(ip)
Out[5]: "IPAddress('192.168.2.151')"

In [6]: ip
Out[6]: IPAddress('192.168.2.151')

In [7]: str(ip)
Out[7]: '192.168.2.151'

In [8]: '%s' % ip
Out[8]: '192.168.2.151'

In [9]: ip.format()
Out[9]: '192.168.2.151'
可以查看ip地址的其他进制格式:

In [11]: int(ip)
Out[11]: 3232236183L

In [12]: hex(ip)
Out[12]: '0xc0a80297'

In [13]: ip.bin
Out[13]: '0b11000000101010000000001010010111'

In [14]: ip.bits()
Out[14]: '11000000.10101000.00000010.10010111'

In [15]: ip.words == (192,168,2,151)
Out[15]: True


网络/子网

IPNetwork: IPNetwork模块用于处理子网、子网掩码、 CIDR表示的 VLAN或网络

In [18]: ip = IPNetwork('192.168.2.151')

In [19]: ip.ip
Out[19]: IPAddress('192.168.2.151')

In [20]: ip.network, ip.broadcast
Out[20]: (IPAddress('192.168.2.151'), IPAddress('192.168.2.151'))

In [21]: ip.size
Out[21]: 1
上述情况下,网络和广播地址是一样的,如果采用CIDR地址块,则:

In [22]: ip = IPNetwork('192.168.2.151/24')

In [23]: ip.ip
Out[23]: IPAddress('192.168.2.151')

In [24]: ip.network, ip.broadcast
Out[24]: (IPAddress('192.168.2.0'), IPAddress('192.168.2.255'))

In [25]: ip.netmask, ip.hostmask
Out[25]: (IPAddress('255.255.255.0'), IPAddress('0.0.0.255'))<pre name="code" class="python">

In [26]: ip.size
Out[26]: 256

 上述结果得到了相应的ip地址,子网地址,广播地址,IP掩码和主机号掩码以及该网络容纳ip的数量。对应一个已有的IPNetwork,同样可以更改ip地址和CIDR的前缀: 

In [27]: ip = IPNetwork('0.0.0.0/0')

In [28]: ip
Out[28]: IPNetwork('0.0.0.0/0')

In [29]: ip.value = 3221225985

In [30]: ip
Out[30]: IPNetwork('192.0.2.1/0')

In [31]: ip.prefixlen
Out[31]: 0

In [32]: ip.prefixlen=23

In [33]: ip
Out[33]: IPNetwork('192.0.2.1/23')


IPNetwork同样提供了一些属性能够直接得到真正的带有CIDR前缀的CIDR地址(已经从网络地址中移除了主机地址):

In [35]: ip.cidr
Out[35]: IPNetwork('192.0.2.0/23')


如果你想用二进制来更直观地查看地址(ip地址、网络地址、子网掩码、广播地址等),可以由以下方法:

In [36]: ip.ip.bits()
Out[36]: '11000000.00000000.00000010.00000001'

In [37]: ip.network.bits()
Out[37]: '11000000.00000000.00000010.00000000'

In [38]: ip.netmask.bits()
Out[38]: '11111111.11111111.11111110.00000000'

In [39]: ip.broadcast.bits()
Out[39]: '11000000.00000000.00000011.11111111'

IPv6

netaddr还提供了对IPv6的支持,例如:

In [40]: ip = IPAddress(0,6)

In [41]: ip
Out[41]: IPAddress('::')

In [43]: ip = IPNetwork('fe80::dead:beef/64')

In [44]: str(ip), ip.prefixlen, ip.version
Out[44]: ('fe80::dead:beef/64', 64, 6)

In [45]: int(ip.ip)
Out[45]: 338288524927261089654018896845083623151L

In [46]: hex(ip.ip)
Out[46]: '0xfe8000000000000000000000deadbeef'


对于IPv4上的操作同样适用于IPv6:

In [47]: ip.ip.bits()
Out[47]: '1111111010000000:0000000000000000:0000000000000000:0000000000000000:0000000000000000:0000000000000000:1101111010101101:1011111011101111'

In [48]: ip.network, ip.broadcast, ip.netmask, ip.hostmask
Out[48]: 
(IPAddress('fe80::'),
 IPAddress('fe80::ffff:ffff:ffff:ffff'),
 IPAddress('ffff:ffff:ffff:ffff::'),
 IPAddress('::ffff:ffff:ffff:ffff'))

IPv6转IPv4

In [50]: IPNetwork('::ffff:192.0.2.1/119').ipv6()
Out[50]: IPNetwork('::ffff:192.0.2.1/119')

In [52]: IPNetwork('::ffff:192.0.2.1/119').ipv6(ipv4_compatible=True)
Out[52]: IPNetwork('::192.0.2.1/119')

In [53]: IPNetwork('::ffff:192.0.2.1/119').ipv4()
Out[53]: IPNetwork('192.0.2.1/23')

In [54]: IPNetwork('::192.0.2.1/119').ipv4()
Out[54]: IPNetwork('192.0.2.1/23')

IP 列表

使用 IPNetwork模块来进行网络操作,事实上,返回的是一个IPNetwork类型,要得到网段内的ip地址列表,需要调用list方法:

In [2]: ip = IPNetwork('192.168.2.151/29')

In [3]: type(ip)
Out[3]: netaddr.ip.IPNetwork

In [4]: type(ip[0:-1])
Out[4]: generator

In [5]: ip_list = list(ip)

In [6]: ip_list
Out[6]: 
[IPAddress('192.168.2.144'),
 IPAddress('192.168.2.145'),
 IPAddress('192.168.2.146'),
 IPAddress('192.168.2.147'),
 IPAddress('192.168.2.148'),
 IPAddress('192.168.2.149'),
 IPAddress('192.168.2.150'),
 IPAddress('192.168.2.151')]

In [7]: ip[-1]
Out[7]: IPAddress('192.168.2.151')

In [8]: ip[0]
Out[8]: IPAddress('192.168.2.144')

In [9]: ip[0:4]
Out[9]: <generator object iter_iprange at 0xb61ec414>

In [10]: list(ip[0::2])
Out[10]: 
[IPAddress('192.168.2.144'),
 IPAddress('192.168.2.146'),
 IPAddress('192.168.2.148'),
 IPAddress('192.168.2.150')]

In [11]: list(ip[-1::-1])
Out[11]: 
[IPAddress('192.168.2.151'),
 IPAddress('192.168.2.150'),
 IPAddress('192.168.2.149'),
 IPAddress('192.168.2.148'),
 IPAddress('192.168.2.147'),
 IPAddress('192.168.2.146'),
 IPAddress('192.168.2.145'),
 IPAddress('192.168.2.144')]
 可见,ip[XXX]的形式其实就是一个生成器,生成器的目的是保证在处理拥有大量ip的网络时降低对资源的占用。 
In [15]: for ip in IPNetwork('192.0.2.0/23'):
   ....:     print ip
out [15]:
192.0.2.0
192.0.2.1
192.0.2.2
192.0.2.3
...
192.0.3.252
192.0.3.253
192.0.3.254
192.0.3.255
上述结果中:192.0.2.0和192.0.3.255并不是有效的主机地址,而是网络地址和广播地址。为了得到有效的主机地址,则需要使用iter_hosts()
[16]:for ip in IPNetwork('192.0.2.0/23').iter_hosts():
...     print '%s' % ip
out [16]: 
192.0.2.1
192.0.2.2
192.0.2.3
192.0.2.4
...
192.0.3.251
192.0.3.252
192.0.3.253
192.0.3.254

排序

对IP和网络进行排序的方法是使用sorted函数:

In [16]: ip_list = list(IPNetwork('192.0.2.128/28'))

In [17]: sorted(ip_list)
Out[17]: 
[IPAddress('192.0.2.128'),
 IPAddress('192.0.2.129'),
 IPAddress('192.0.2.130'),
 IPAddress('192.0.2.131'),
 IPAddress('192.0.2.132'),
 IPAddress('192.0.2.133'),
 IPAddress('192.0.2.134'),
 IPAddress('192.0.2.135'),
 IPAddress('192.0.2.136'),
 IPAddress('192.0.2.137'),
 IPAddress('192.0.2.138'),
 IPAddress('192.0.2.139'),
 IPAddress('192.0.2.140'),
 IPAddress('192.0.2.141'),
 IPAddress('192.0.2.142'),
 IPAddress('192.0.2.143')]

为了方便起见,也可以对网络进行排序,并且IPv4和IPv6网络可以混排。例如:

In [18]: ip_list = [
   ....: IPAddress('192.0.2.130'),
   ....: IPAddress('10.0.0.1'),
   ....: IPNetwork('192.0.2.128/28'),
   ....: IPNetwork('192.0.3.0/24'),
   ....: IPNetwork('192.0.2.0/24'),
   ....: IPNetwork('fe80::/64'),
   ....: IPAddress('::'),
   ....: IPNetwork('172.24/12')]

In [19]: import random

In [20]: random.shuffle(ip_list)

In [21]: ip_list.sort()

In [23]: import pprint

In [24]: pprint.pprint(ip_list)
[IPAddress('10.0.0.1'),
 IPNetwork('172.24.0.0/12'),
 IPNetwork('192.0.2.0/24'),
 IPNetwork('192.0.2.128/28'),
 IPAddress('192.0.2.130'),
 IPNetwork('192.0.3.0/24'),
 IPAddress('::'),
 IPNetwork('fe80::/64')]

IP地址分类

IP地址有许多分类,并不是每个ip地址都能够做为主机地址。

单播地址(Unicast)

In [25]: IPAddress('192.0.2.1').is_unicast()
Out[25]: True

In [26]: IPAddress('fe80::1').is_unicast()
Out[26]: True

多播地址(Multicast)

In [27]: IPAddress('239.192.0.1').is_multicast()
Out[27]: True

In [28]:  IPAddress('ff00::1').is_multicast()
Out[28]: True

私有地址(Private)

In [29]: IPAddress('172.24.0.1').is_private()
Out[29]: True

In [30]: IPAddress('10.0.0.1').is_private()
Out[30]: True

In [31]: IPAddress('192.168.0.1').is_private()
Out[31]: True

In [32]: IPAddress('fc00::1').is_private()
Out[32]: True

保留地址(Reserved)

In [33]: IPAddress('253.0.0.1').is_reserved()
Out[33]: True

公网地址(Public)

In [34]: ip = IPAddress('62.125.24.5')

In [35]: ip.is_unicast() and not ip.is_private()
Out[35]: True

子网掩码(Netmasks)与主机掩码(Hostmasks)

In [36]: IPAddress('255.255.254.0').is_netmask()
Out[36]: True

In [37]: IPAddress('0.0.1.255').is_hostmask()
Out[37]: True


回环地址(loopback)

In [38]: IPAddress('127.0.0.1').is_loopback()
Out[38]: True

In [39]: IPAddress('::1').is_loopback()
Out[39]: True

IP地址比较

IPAddress对象还可以进行彼此比较。IPAdrees可以代表某个具体的ip地址,也可以代表某个只有单个主机的网络,因此在比较ip地址之前,应转换成同一类型,以避免出现奇怪的结果。
In [42]: IPAddress('192.0.2.1') == IPAddress('192.0.2.1')
Out[42]: True

In [43]: IPAddress('192.0.2.1') < IPAddress('192.0.2.2')
Out[43]: True

In [44]: IPAddress('192.0.2.1') <= IPAddress('192.0.2.1')
Out[44]: True

In [45]: IPAddress('192.0.2.1') <= IPAddress('192.0.2.2')
Out[45]: True

而对于IPNetwork而言,比较的是两个子网而非两个ip地址:
In [46]: IPNetwork('192.0.2.0/24') == IPNetwork('192.0.2.112/24')
Out[46]: True
若要比较其ip,则只需取其ip属性即可:
In [47]: IPNetwork('192.0.2.0/24').ip == IPNetwork('192.0.2.112/24').ip
Out[47]: False

In [48]: IPNetwork('192.0.2.0/24').ip < IPNetwork('192.0.2.112/24').ip
Out[48]: True
或者直接明确比较cidr网络地址:
<pre name="code" class="plain">In [49]: IPNetwork('192.0.2.0/24').cidr == IPNetwork('192.0.2.112/24').cidr
Out[49]: True
 
 注意:IPAddress(标量)和IPNetwork(向量)不能直接比较,如果非要比较的话,则要具体指明IPNetwork的哪个值。比如: 
In [50]:  IPAddress('192.0.2.0') == IPNetwork('192.0.2.0/32')[0]
Out[50]: True

In [51]: IPAddress('192.0.2.0') == IPNetwork('192.0.2.0/32')[-1]
Out[51]: True

In [52]: IPAddress('192.0.2.0') != IPNetwork('192.0.2.0/32')[0]
Out[52]: False

非标准IP分布

如果要要得到从IP地址A到IP地址B之间的网络,那么需要计算CIDR或子网地址,这无疑是件痛苦的事情。而netaddr提供一种很好的解决方法。
In [55]: r1 = IPRange('192.0.2.1', '192.0.2.15')

In [56]: r1.cidrs()
Out[56]: 
[IPNetwork('192.0.2.1/32'),
 IPNetwork('192.0.2.2/31'),
 IPNetwork('192.0.2.4/30'),
 IPNetwork('192.0.2.8/29')]
	
下面是IPRange和IPNetwork之间的比较:
In [58]: IPRange('192.0.2.0', '192.0.2.255') != IPNetwork('192.0.2.0/24')
Out[58]: False

In [59]: IPRange('192.0.2.0', '192.0.2.255') == IPNetwork('192.0.2.0/24')
Out[59]: True
如果想要得到IPRange中的IP地址,则用list:
In [60]: r1 = IPRange('192.0.2.1', '192.0.2.15')

In [61]: addrs = list(r1)

In [62]: addrs
Out[62]: 
[IPAddress('192.0.2.1'),
 IPAddress('192.0.2.2'),
 IPAddress('192.0.2.3'),
 IPAddress('192.0.2.4'),
 IPAddress('192.0.2.5'),
 IPAddress('192.0.2.6'),
 IPAddress('192.0.2.7'),
 IPAddress('192.0.2.8'),
 IPAddress('192.0.2.9'),
 IPAddress('192.0.2.10'),
 IPAddress('192.0.2.11'),
 IPAddress('192.0.2.12'),
 IPAddress('192.0.2.13'),
 IPAddress('192.0.2.14'),
 IPAddress('192.0.2.15')]

In [63]: r1 == addrs
Out[63]: False
强调一点,若要比较,必须是同类型的才行(才有意义)。但是如果有一个序列包含IPAddress、IPNetwork和string类型的ip地址时该怎么办?IPSet类可以处理IP地址和网络组成的组。
In [64]: ips = [IPAddress('192.0.2.1'), '192.0.2.2/31', IPNetwork('192.0.2.4/31'), IPAddress('192.0.2.6'), IPAddress('192.0.2.7'), '192.0.2.8', '192.0.2.9', IPAddress('192.0.2.10'), IPAddress('192.0.2.11'), IPNetwork('192.0.2.12/30')]

In [67]: s1 = IPSet(r1.cidrs())

In [68]: s2 = IPSet(ips)

In [69]: s1
Out[69]: IPSet(['192.0.2.1/32', '192.0.2.2/31', '192.0.2.4/30', '192.0.2.8/29'])

In [70]: s2
Out[70]: IPSet(['192.0.2.1/32', '192.0.2.2/31', '192.0.2.4/30', '192.0.2.8/29'])

In [71]: s1 == s2
Out[71]: True
那么当从IPSet中移除一个元素,看看会发生什么事情:
In [72]: s2.pop()
Out[72]: IPNetwork('192.0.2.4/30')

In [73]: s1 == s2
Out[73]: False
更多IPSet教程请参看 官网教程。另一种是使用Glob方法表示IP范围,即模式匹配的方法来表示IP地址范围。例如:
In [75]: IPGlob('192.0.2.*') == IPNetwork('192.0.2.0/24')
Out[75]: True
由于IPGlob是IPRange的一个子类,所以IPRange的所有方法都适合于IPGlob,IPGlob暂时只适用于IPv4。









  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值