如何找到本地IP地址(即192.168.x。x或10.0.x.x)在Python平台独立,只使用标准库?
当前回答
使用新引入的asyncio包的Python 3.4版本。
async def get_local_ip():
loop = asyncio.get_event_loop()
transport, protocol = await loop.create_datagram_endpoint(
asyncio.DatagramProtocol,
remote_addr=('8.8.8.8', 80))
result = transport.get_extra_info('sockname')[0]
transport.close()
return result
这是基于UnkwnTech的精彩回答。
其他回答
此方法返回本地盒子上的“主”IP(具有默认路由的IP)。
不需要可路由的网络访问或任何连接。 即使所有接口都从网络断开,也能正常工作。 不需要甚至不尝试去其他地方。 工作与NAT,公共,私有,外部和内部IP 没有外部依赖的纯Python 2(或3)。 支持Linux、Windows和OSX。
Python 3或2:
import socket
def get_ip():
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.settimeout(0)
try:
# doesn't even have to be reachable
s.connect(('10.254.254.254', 1))
IP = s.getsockname()[0]
except Exception:
IP = '127.0.0.1'
finally:
s.close()
return IP
print(get_ip())
这将返回一个主IP(具有默认路由的IP)。如果您需要将所有IP附加到所有接口(包括localhost等),请参见类似这样的回答。
如果你在一个NAT防火墙后面,比如你家里的wifi路由器,那么这将不会显示你的公共NAT IP,而是显示你在本地网络上的私有IP,它有一个默认路由到你的本地wifi路由器。如果你需要外部IP:
在那个外部设备(wifi路由器)上运行这个功能,或者 连接到外部服务(如https://www.ipify.org/),可以反射从外部世界看到的IP
... 但这些想法与最初的问题完全不同。:)
恐怕除了连接到另一台计算机并让它把你的IP地址发送给你之外,没有任何好的独立于平台的方法来做到这一点。例如:findmyipaddress。注意,如果你需要一个NAT后的IP地址,除非你所连接的计算机也是NAT后的IP地址,这是行不通的。
下面是一个适用于Linux的解决方案:获取与网络接口关联的IP地址。
[仅限Windows]如果您不想使用外部包,也不想依赖外部Internet服务器,这可能会有所帮助。这是一个代码样本,我在谷歌代码搜索和修改返回所需的信息:
def getIPAddresses():
from ctypes import Structure, windll, sizeof
from ctypes import POINTER, byref
from ctypes import c_ulong, c_uint, c_ubyte, c_char
MAX_ADAPTER_DESCRIPTION_LENGTH = 128
MAX_ADAPTER_NAME_LENGTH = 256
MAX_ADAPTER_ADDRESS_LENGTH = 8
class IP_ADDR_STRING(Structure):
pass
LP_IP_ADDR_STRING = POINTER(IP_ADDR_STRING)
IP_ADDR_STRING._fields_ = [
("next", LP_IP_ADDR_STRING),
("ipAddress", c_char * 16),
("ipMask", c_char * 16),
("context", c_ulong)]
class IP_ADAPTER_INFO (Structure):
pass
LP_IP_ADAPTER_INFO = POINTER(IP_ADAPTER_INFO)
IP_ADAPTER_INFO._fields_ = [
("next", LP_IP_ADAPTER_INFO),
("comboIndex", c_ulong),
("adapterName", c_char * (MAX_ADAPTER_NAME_LENGTH + 4)),
("description", c_char * (MAX_ADAPTER_DESCRIPTION_LENGTH + 4)),
("addressLength", c_uint),
("address", c_ubyte * MAX_ADAPTER_ADDRESS_LENGTH),
("index", c_ulong),
("type", c_uint),
("dhcpEnabled", c_uint),
("currentIpAddress", LP_IP_ADDR_STRING),
("ipAddressList", IP_ADDR_STRING),
("gatewayList", IP_ADDR_STRING),
("dhcpServer", IP_ADDR_STRING),
("haveWins", c_uint),
("primaryWinsServer", IP_ADDR_STRING),
("secondaryWinsServer", IP_ADDR_STRING),
("leaseObtained", c_ulong),
("leaseExpires", c_ulong)]
GetAdaptersInfo = windll.iphlpapi.GetAdaptersInfo
GetAdaptersInfo.restype = c_ulong
GetAdaptersInfo.argtypes = [LP_IP_ADAPTER_INFO, POINTER(c_ulong)]
adapterList = (IP_ADAPTER_INFO * 10)()
buflen = c_ulong(sizeof(adapterList))
rc = GetAdaptersInfo(byref(adapterList[0]), byref(buflen))
if rc == 0:
for a in adapterList:
adNode = a.ipAddressList
while True:
ipAddr = adNode.ipAddress
if ipAddr:
yield ipAddr
adNode = adNode.next
if not adNode:
break
用法:
>>> for addr in getIPAddresses():
>>> print addr
192.168.0.100
10.5.9.207
由于它依赖于windll,这将只在Windows上工作。
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.
在拥有iproute2实用程序的现代*NIX系统上,您可以通过subprocess.run()调用它,因为您可以使用-j开关在JSON中输出,然后使用JSON .loads()模块和方法将其转换为python数据结构。下面的代码显示第一个非环回IP地址。
import subprocess
import json
ip = json.loads(subprocess.run('ip -j a'.split(),capture_output=True).stdout.decode())[1]['addr_info'][0]['local']
print(ip)
或者,如果你有多个IP,并且想要找到连接到特定目的地的IP,你可以使用IP -j route get 8.8.8.8,如下所示:
import subprocess
import json
ip = json.loads(subprocess.run('ip -j route get 8.8.8.8'.split(),capture_output=True).stdout.decode())[0]['prefsrc']
print(ip)
如果你在寻找所有的IP地址,你可以遍历IP -j a返回的字典列表
import subprocess
import json
list_of_dicts = json.loads(subprocess.run('ip -j a'.split(),capture_output=True).stdout.decode())
for interface in list_of_dicts:
try:print(f"Interface: {interface['ifname']:10} IP: {interface['addr_info'][0]['local']}")
except:pass
推荐文章
- 从matplotlib中的颜色映射中获取单个颜色
- 将Pandas或Numpy Nan替换为None以用于MysqlDB
- 使用pandas对同一列进行多个聚合
- 使用Python解析HTML
- django MultiValueDictKeyError错误,我如何处理它
- 如何在for循环期间修改列表条目?
- 我如何在Django中创建一个鼻涕虫?
- 没有名为'django.core.urlresolvers'的模块
- 蟒蛇导出环境文件
- Django - makemigrations -未检测到任何更改
- SQLAlchemy:引擎、连接和会话差异
- 在Python Pandas中删除多个列中的所有重复行
- 更改pandas DataFrame中的特定列名
- 将Pandas多索引转换为列
- 熊猫在每组中获得最高的n个记录