Python获取ip地址

来源:互联网 发布:linux 没有tmp文件夹 编辑:程序博客网 时间:2024/06/05 15:31

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 netifacesdef 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 ipsips = 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 pprintIn [3]: ip = IPAddress("192.168.2.151")In [4]: ip.versionOut[4]: 4In [5]: repr(ip)Out[5]: "IPAddress('192.168.2.151')"In [6]: ipOut[6]: IPAddress('192.168.2.151')In [7]: str(ip)Out[7]: '192.168.2.151'In [8]: '%s' % ipOut[8]: '192.168.2.151'In [9]: ip.format()Out[9]: '192.168.2.151'
可以查看ip地址的其他进制格式:

In [11]: int(ip)Out[11]: 3232236183LIn [12]: hex(ip)Out[12]: '0xc0a80297'In [13]: ip.binOut[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.ipOut[19]: IPAddress('192.168.2.151')In [20]: ip.network, ip.broadcastOut[20]: (IPAddress('192.168.2.151'), IPAddress('192.168.2.151'))In [21]: ip.sizeOut[21]: 1
上述情况下,网络和广播地址是一样的,如果采用CIDR地址块,则:

In [22]: ip = IPNetwork('192.168.2.151/24')In [23]: ip.ipOut[23]: IPAddress('192.168.2.151')In [24]: ip.network, ip.broadcastOut[24]: (IPAddress('192.168.2.0'), IPAddress('192.168.2.255'))In [25]: ip.netmask, ip.hostmaskOut[25]: (IPAddress('255.255.255.0'), IPAddress('0.0.0.255'))<pre name="code" class="python">

In [26]: ip.sizeOut[26]: 256

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

In [27]: ip = IPNetwork('0.0.0.0/0')In [28]: ipOut[28]: IPNetwork('0.0.0.0/0')In [29]: ip.value = 3221225985In [30]: ipOut[30]: IPNetwork('192.0.2.1/0')In [31]: ip.prefixlenOut[31]: 0In [32]: ip.prefixlen=23In [33]: ipOut[33]: IPNetwork('192.0.2.1/23')


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

In [35]: ip.cidrOut[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]: ipOut[41]: IPAddress('::')In [43]: ip = IPNetwork('fe80::dead:beef/64')In [44]: str(ip), ip.prefixlen, ip.versionOut[44]: ('fe80::dead:beef/64', 64, 6)In [45]: int(ip.ip)Out[45]: 338288524927261089654018896845083623151LIn [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.hostmaskOut[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.IPNetworkIn [4]: type(ip[0:-1])Out[4]: generatorIn [5]: ip_list = list(ip)In [6]: ip_listOut[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 ipout [15]:192.0.2.0192.0.2.1192.0.2.2192.0.2.3...192.0.3.252192.0.3.253192.0.3.254192.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' % ipout [16]: 192.0.2.1192.0.2.2192.0.2.3192.0.2.4...192.0.3.251192.0.3.252192.0.3.253192.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 randomIn [20]: random.shuffle(ip_list)In [21]: ip_list.sort()In [23]: import pprintIn [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]: TrueIn [26]: IPAddress('fe80::1').is_unicast()Out[26]: True

多播地址(Multicast)

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

私有地址(Private)

In [29]: IPAddress('172.24.0.1').is_private()Out[29]: TrueIn [30]: IPAddress('10.0.0.1').is_private()Out[30]: TrueIn [31]: IPAddress('192.168.0.1').is_private()Out[31]: TrueIn [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]: TrueIn [37]: IPAddress('0.0.1.255').is_hostmask()Out[37]: True


回环地址(loopback)

In [38]: IPAddress('127.0.0.1').is_loopback()Out[38]: TrueIn [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]: TrueIn [43]: IPAddress('192.0.2.1') < IPAddress('192.0.2.2')Out[43]: TrueIn [44]: IPAddress('192.0.2.1') <= IPAddress('192.0.2.1')Out[44]: TrueIn [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').ipOut[47]: FalseIn [48]: IPNetwork('192.0.2.0/24').ip < IPNetwork('192.0.2.112/24').ipOut[48]: True
或者直接明确比较cidr网络地址:
<pre name="code" class="plain">In [49]: IPNetwork('192.0.2.0/24').cidr == IPNetwork('192.0.2.112/24').cidrOut[49]: True
注意:IPAddress(标量)和IPNetwork(向量)不能直接比较,如果非要比较的话,则要具体指明IPNetwork的哪个值。比如:
In [50]:  IPAddress('192.0.2.0') == IPNetwork('192.0.2.0/32')[0]Out[50]: TrueIn [51]: IPAddress('192.0.2.0') == IPNetwork('192.0.2.0/32')[-1]Out[51]: TrueIn [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]: FalseIn [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]: addrsOut[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 == addrsOut[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]: s1Out[69]: IPSet(['192.0.2.1/32', '192.0.2.2/31', '192.0.2.4/30', '192.0.2.8/29'])In [70]: s2Out[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 == s2Out[71]: True
那么当从IPSet中移除一个元素,看看会发生什么事情:
In [72]: s2.pop()Out[72]: IPNetwork('192.0.2.4/30')In [73]: s1 == s2Out[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 0
原创粉丝点击