如何找到本地IP地址(即192.168.x。x或10.0.x.x)在Python平台独立,只使用标准库?
当前回答
要获取ip地址,可以直接在python中使用shell命令:
import socket, subprocess
def get_ip_and_hostname():
hostname = socket.gethostname()
shell_cmd = "ifconfig | awk '/inet addr/{print substr($2,6)}'"
proc = subprocess.Popen([shell_cmd], stdout=subprocess.PIPE, shell=True)
(out, err) = proc.communicate()
ip_list = out.split('\n')
ip = ip_list[0]
for _ip in ip_list:
try:
if _ip != "127.0.0.1" and _ip.split(".")[3] != "1":
ip = _ip
except:
pass
return ip, hostname
ip_addr, hostname = get_ip_and_hostname()
其他回答
import socket
socket.gethostbyname(socket.gethostname())
这并不总是有效(在/etc/hosts主机名为127.0.0.1的机器上返回127.0.0.1),gimel显示的是一个缓和的方法,使用socket.getfqdn()代替。当然,您的机器需要一个可解析的主机名。
通过命令行utils产生“干净”输出的一个简单方法:
import commands
ips = commands.getoutput("/sbin/ifconfig | grep -i \"inet\" | grep -iv \"inet6\" | " +
"awk {'print $2'} | sed -ne 's/addr\:/ /p'")
print ips
它将显示系统上的所有IPv4地址。
Netifaces可通过PIP和easy_install获得。(我知道,它不在基础,但它可能值得安装。)
Netifaces在不同平台上确实有一些奇怪之处:
localhost/loop-back接口可能并不总是包含在内(Cygwin)。 地址按协议列出(例如IPv4, IPv6),协议按接口列出。在某些系统(Linux)上,每个协议-接口对都有自己的关联接口(使用interface_name:n表示法),而在其他系统(Windows)上,单个接口将有每个协议的地址列表。在这两种情况下都有一个协议列表,但它可能只包含一个元素。
下面是一些netifaces代码:
import netifaces
PROTO = netifaces.AF_INET # We want only IPv4, for now at least
# Get list of network interfaces
# Note: Can't filter for 'lo' here because Windows lacks it.
ifaces = netifaces.interfaces()
# Get all addresses (of all kinds) for each interface
if_addrs = [netifaces.ifaddresses(iface) for iface in ifaces]
# Filter for the desired address type
if_inet_addrs = [addr[PROTO] for addr in if_addrs if PROTO in addr]
iface_addrs = [s['addr'] for a in if_inet_addrs for s in a if 'addr' in s]
# Can filter for '127.0.0.1' here.
上面的代码没有将地址映射回接口名(对于动态生成ebtables/iptables规则很有用)。所以这里有一个版本,它将上述信息和接口名称保存在一个元组中:
import netifaces
PROTO = netifaces.AF_INET # We want only IPv4, for now at least
# Get list of network interfaces
ifaces = netifaces.interfaces()
# Get addresses for each interface
if_addrs = [(netifaces.ifaddresses(iface), iface) for iface in ifaces]
# Filter for only IPv4 addresses
if_inet_addrs = [(tup[0][PROTO], tup[1]) for tup in if_addrs if PROTO in tup[0]]
iface_addrs = [(s['addr'], tup[1]) for tup in if_inet_addrs for s in tup[0] if 'addr' in s]
而且,不,我不喜欢列表理解。这些天我的大脑就是这么运转的。
下面的代码段将全部打印出来:
from __future__ import print_function # For 2.x folks
from pprint import pprint as pp
print('\nifaces = ', end='')
pp(ifaces)
print('\nif_addrs = ', end='')
pp(if_addrs)
print('\nif_inet_addrs = ', end='')
pp(if_inet_addrs)
print('\niface_addrs = ', end='')
pp(iface_addrs)
享受吧!
Socket API方法
参见https://stackoverflow.com/a/28950776/711085
缺点:
Not cross-platform. Requires more fallback code, tied to existence of particular addresses on the internet This will also not work if you're behind a NAT Probably creates a UDP connection, not independent of (usually ISP's) DNS availability (see other answers for ideas like using 8.8.8.8: Google's (coincidentally also DNS) server) Make sure you make the destination address UNREACHABLE, like a numeric IP address that is spec-guaranteed to be unused. Do NOT use some domain like fakesubdomain.google.com or somefakewebsite.com; you'll still be spamming that party (now or in the future), and spamming your own network boxes as well in the process.
反射器方法
(请注意,这并没有回答OP的本地IP地址问题,例如192.168…;它会给你你的公共IP地址,根据用例,这可能更可取。)
你可以查询一些网站,如whatismyip.com(但有一个API),例如:
from urllib.request import urlopen
import re
def getPublicIp():
data = str(urlopen('http://checkip.dyndns.com/').read())
# data = '<html><head><title>Current IP Check</title></head><body>Current IP Address: 65.96.168.198</body></html>\r\n'
return re.compile(r'Address: (\d+\.\d+\.\d+\.\d+)').search(data).group(1)
或者如果使用python2:
from urllib import urlopen
import re
def getPublicIp():
data = str(urlopen('http://checkip.dyndns.com/').read())
# data = '<html><head><title>Current IP Check</title></head><body>Current IP Address: 65.96.168.198</body></html>\r\n'
return re.compile(r'Address: (\d+\.\d+\.\d+\.\d+)').search(data).group(1)
优点:
这种方法的一个优点是它是跨平台的 它从丑陋的nat(例如你的家用路由器)后面工作。
缺点(和变通方法):
要求网站正常运行,格式不变(几乎肯定不会),DNS服务器正常工作。在失败的情况下,还可以通过查询其他第三方IP地址反射器来缓解这个问题。 如果您不查询多个反射器(以防止一个受损害的反射器告诉您您的地址不是某个东西),或者如果您不使用HTTPS(以防止假装是服务器的中间人攻击),则可能的攻击向量
edit: Though initially I thought these methods were really bad (unless you use many fallbacks, the code may be irrelevant many years from now), it does pose the question "what is the internet?". A computer may have many interfaces pointing to many different networks. For a more thorough description of the topic, google for gateways and routes. A computer may be able to access an internal network via an internal gateway, or access the world-wide web via a gateway on for example a router (usually the case). The local IP address that the OP asks about is only well-defined with respect to a single link layer, so you have to specify that ("is it the network card, or the ethernet cable, which we're talking about?"). There may be multiple non-unique answers to this question as posed. However the global IP address on the world-wide web is probably well-defined (in the absence of massive network fragmentation): probably the return path via the gateway which can access the TLDs.
供您参考,我可以验证该方法:
import socket
addr = socket.gethostbyname(socket.gethostname())
适用于OS X (10.6,10.5), Windows XP和管理良好的RHEL部门服务器。它不能在一个非常小的CentOS虚拟机上工作,我只是做了一些内核黑客。因此,对于该实例,您可以检查127.0.0.1地址,在这种情况下,执行以下操作:
if addr == "127.0.0.1":
import commands
output = commands.getoutput("/sbin/ifconfig")
addr = parseaddress(output)
然后从输出中解析ip地址。应该注意的是,默认情况下ifconfig不在普通用户的PATH中,这就是为什么我在命令中给出完整的路径。我希望这能有所帮助。
推荐文章
- 证书验证失败:无法获得本地颁发者证书
- 当使用pip3安装包时,“Python中的ssl模块不可用”
- 无法切换Python与pyenv
- Python if not == vs if !=
- 如何从scikit-learn决策树中提取决策规则?
- 为什么在Mac OS X v10.9 (Mavericks)的终端中apt-get功能不起作用?
- 将旋转的xtick标签与各自的xtick对齐
- 为什么元组可以包含可变项?
- 如何合并字典的字典?
- 如何创建类属性?
- 不区分大小写的“in”
- 在Python中获取迭代器中的元素个数
- 解析日期字符串并更改格式
- 使用try和。Python中的if
- 如何在Python中获得所有直接子目录