【问题标题】:Getting a machine's external IP address with Python使用 Python 获取机器的外部 IP 地址
【发布时间】:2011-01-19 16:05:09
【问题描述】:

正在寻找一种更好的方法来获取机器当前的外部 IP #...以下工作,但宁愿不依赖外部站点来收集信息...我仅限于使用捆绑的标准 Python 2.5.1 库使用 Mac OS X 10.5.x

import os
import urllib2

def check_in():

    fqn = os.uname()[1]
    ext_ip = urllib2.urlopen('http://whatismyip.org').read()
    print ("Asset: %s " % fqn, "Checking in from IP#: %s " % ext_ip)

【问题讨论】:

标签: python standard-library


【解决方案1】:

我喜欢http://ipify.org。他们甚至提供 Python 代码来使用他们的 API。

# This example requires the requests library be installed.  You can learn more
# about the Requests library here: http://docs.python-requests.org/en/latest/
from requests import get

ip = get('https://api.ipify.org').content.decode('utf8')
print('My public IP address is: {}'.format(ip))

【讨论】:

    【解决方案2】:

    Python3,只使用标准库

    如前所述,可以使用external service 之类的https://ident.me 来发现路由器的外部IP 地址。

    下面是使用python3 的方法,只使用the standard library:

    import urllib.request
    
    external_ip = urllib.request.urlopen('https://ident.me').read().decode('utf8')
    
    print(external_ip)
    

    【讨论】:

    • 虽然 OP 适用于 python 2,但我认为这应该是 Python 3 的公认答案,因为它不使用任何第三方库。但是请注意,ident.me(以及其他类似ipv4bot.whatismyipaddress.com)请求所花费的时间大约是api.ipify.orgipinfo.io/ip 所需的两倍,使用与此答案相同的代码。我发现(在六个中)最快和最简单的响应是 api.ipify.org。
    • @Oliver 按照您的建议,我测试了api.ipify.orgident.me 在欧洲这里,ident.me 的速度大约是api.ipify.org 的三倍我知道您位于加拿大。
    • Serge haha​​ 很高兴知道这是有道理的,感谢您的反馈。是的加拿大。
    • 请注意,当我从主机使用 ident.me 时,它返回了 IPv6 地址,而其他人从同一位置返回了 IPv4 地址。
    • Indeed ident.me 来自欧洲(以前是英国,现在是德国)。 @jcoppen 您正在查看专门针对 IPv4 的 v4.ident.me; api.ident.me 了解更多信息 :)
    【解决方案3】:

    如果您在获取外部IP的路由器后面,恐怕您别无选择,只能像您一样使用外部服务。如果路由器本身有一些查询接口,你可以使用它,但解决方案会非常依赖环境且不可靠。

    【讨论】:

    • 是的,同意。 AWS&GoogleGCP提供的那些云服务器都只在其本地接口查询中提供内部IP地址。我们必须使用 external 来查询它的公共 IP 地址。
    【解决方案4】:

    您应该使用UPnP protocol 来查询您的路由器以获取此信息。最重要的是,这不依赖于外部服务,这个问题的所有其他答案似乎都暗示了这一点。

    有一个名为 miniupnp 的 Python 库可以做到这一点,参见例如miniupnpc/testupnpigd.py.

    pip install miniupnpc
    

    根据他们的示例,您应该能够执行以下操作:

    import miniupnpc
    
    u = miniupnpc.UPnP()
    u.discoverdelay = 200
    u.discover()
    u.selectigd()
    print('external ip address: {}'.format(u.externalipaddress()))
    

    【讨论】:

    • 即使您连接到 VPN 也可以使用。谢谢
    • 连接到 openvpn 时无法工作。 Exception: No UPnP device discovered
    • 好方法!取决于外部服务可能会以Too many requests 为由阻止请求
    【解决方案5】:

    我更喜欢这个 Amazon AWS 端点:

    import requests
    ip = requests.get('https://checkip.amazonaws.com').text.strip()
    

    【讨论】:

    • 尤其是那些使用boto3的人!
    【解决方案6】:

    我认为最简单的解决方案是

    import requests
    f = requests.request('GET', 'http://myip.dnsomatic.com')
    ip = f.text
    

    就是这样。

    【讨论】:

    • 可能值得一提的是您需要import requests。见pypi.python.org/pypi/requests
    • 不从技术上回答这个问题,因为“Requests 正式支持 Python 2.6–2.7 和 3.3–3.7,并且在 PyPy 上运行良好。”但是,它对其他人仍然有用。
    【解决方案7】:

    试试:

    import requests 
    ip = requests.get('http://ipinfo.io/json').json()['ip']
    

    希望对你有帮助

    【讨论】:

      【解决方案8】:

      使用请求模块:

      import requests
      
      myip = requests.get('https://www.wikipedia.org').headers['X-Client-IP']
      
      print("\n[+] Public IP: "+myip)
      

      【讨论】:

      • 我喜欢这个简单的任务。不需要下载整个页面,我们只需要标题。为此,我建议改用requests.head。效率更高。
      【解决方案9】:

      就像在 Python3 中运行一样简单:

      import os
      
      externalIP  = os.popen('curl -s ifconfig.me').readline()
      print(externalIP)
      

      【讨论】:

      • 这需要安装 curl
      【解决方案10】:

      如果您认为外部来源太不可靠,您可以合并几个不同的服务。对于大多数 ip 查找页面,他们要求您抓取 html,但其中一些已经为像您这样的脚本创建了精简页面 - 也因此他们可以减少他们网站上的点击:

      【讨论】:

        【解决方案11】:

        如果不想使用外部服务(IP网站等),可以使用UPnP Protocol

        为此,我们使用一个简单的 UPnP 客户端库 (https://github.com/flyte/upnpclient)

        安装

        pip install upnpclient

        简单代码

        import upnpclient
        
        devices = upnpclient.discover()
        
        if(len(devices) > 0):
            externalIP = devices[0].WANIPConn1.GetExternalIPAddress()
            print(externalIP)
        else:
            print('No Connected network interface detected')
        

        完整代码(获取 github 自述文件中提到的更多信息)

        In [1]: import upnpclient
        
        In [2]: devices = upnpclient.discover()
        
        In [3]: devices
        Out[3]: 
        [<Device 'OpenWRT router'>,
         <Device 'Harmony Hub'>,
         <Device 'walternate: root'>]
        
        In [4]: d = devices[0]
        
        In [5]: d.WANIPConn1.GetStatusInfo()
        Out[5]: 
        {'NewConnectionStatus': 'Connected',
         'NewLastConnectionError': 'ERROR_NONE',
         'NewUptime': 14851479}
        
        In [6]: d.WANIPConn1.GetNATRSIPStatus()
        Out[6]: {'NewNATEnabled': True, 'NewRSIPAvailable': False}
        
        In [7]: d.WANIPConn1.GetExternalIPAddress()
        Out[7]: {'NewExternalIPAddress': '123.123.123.123'}
        

        【讨论】:

          【解决方案12】:

          我使用 IPGrab 是因为它很容易记住:

          # This example requires the requests library be installed.  You can learn more
          # about the Requests library here: http://docs.python-requests.org/en/latest/
          from requests import get
          
          ip = get('http://ipgrab.io').text
          print('My public IP address is: {}'.format(ip))
          

          【讨论】:

            【解决方案13】:

            还有一些其他方法不依赖 Python 检查外部网站,但操作系统可以。您在这里的主要问题是,即使您没有使用 Python,如果您使用的是命令行,也没有“内置”命令可以简单地告诉您外部(WAN)IP。诸如“ip addr show”和“ifconfig -a”之类的命令会显示服务器在网络中的 IP 地址。只有路由器实际拥有外部 IP。但是,有一些方法可以从命令行查找外部 IP 地址(WAN IP)。

            这些例子是:

            http://ipecho.net/plain ; echo
            curl ipinfo.io/ip
            dig +short myip.opendns.com @resolver1.opendns.com
            dig TXT +short o-o.myaddr.l.google.com @ns1.google.com
            

            因此,python 代码将是:

            import os
            ip = os.popen('wget -qO- http://ipecho.net/plain ; echo').readlines(-1)[0].strip()
            print ip
            

            import os
            iN, out, err = os.popen3('curl ipinfo.io/ip')
            iN.close() ; err.close()
            ip = out.read().strip()
            print ip
            

            import os
            ip = os.popen('dig +short myip.opendns.com @resolver1.opendns.com').readlines(-1)[0].strip()
            print ip
            

            或者,将上述任何其他示例插入到 os.popen、os.popen2、os.popen3 或 os.system 等命令中。

            附:您可以使用“pip3 install pytis”并使用/查看用 Python 编写的“getip”程序。 你也可以在这里找到它的代码:https://github.com/PyTis/PyTis/blob/development/src/pytis/getip.py

            【讨论】:

              【解决方案14】:

              我在这里尝试了有关此问题的大多数其他答案,发现使用的大多数服务都已失效,除了一个。

              这是一个脚本,它应该可以解决问题并且只下载最少量的信息:

              #!/usr/bin/env python
              
              import urllib
              import re
              
              def get_external_ip():
                  site = urllib.urlopen("http://checkip.dyndns.org/").read()
                  grab = re.findall('([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)', site)
                  address = grab[0]
                  return address
              
              if __name__ == '__main__':
                print( get_external_ip() )
              

              【讨论】:

              • 正则表达式已损坏。应该是 \d{1,3}。
              【解决方案15】:
              import requests
              import re
              
              
              def getMyExtIp():
                  try:
                      res = requests.get("http://whatismyip.org")
                      myIp = re.compile('(\d{1,3}\.){3}\d{1,3}').search(res.text).group()
                      if myIp != "":
                          return myIp
                  except:
                      pass
                  return "n/a"
              

              【讨论】:

              • 该死的,这比使用 BeautifulSoup 快一点,谢谢
              【解决方案16】:

              仅限 Linux 的解决方案。

              在 Linux 系统上,您可以使用 Python 在 shell 上执行命令。我认为这可能对某人有所帮助。

              类似这样的东西,(假设 'dig/drill' 正在操作系统上工作)

              import os 
              command = "dig TXT +short o-o.myaddr.l.google.com @ns1.google.com | awk -F\'\"\' '{print $2}' " 
              ip = os.system(command)
              

              对于 Arch 用户,请将 'dig' 替换为 'drill'。

              【讨论】:

              • 导致 sh:1:语法错误:未终止的带引号的字符串
              • @havlock 已更正。请检查。
              【解决方案17】:

              如果机器是防火墙,那么您的解决方案是一个非常明智的解决方案:能够查询防火墙的替代方案最终非常依赖于防火墙的类型(如果可能的话)。

              【讨论】:

                【解决方案18】:

                我能想到的最简单(非python)的工作解决方案是

                wget -q -O- icanhazip.com
                

                我想添加一个非常简短的 Python3 解决方案,它利用 http://hostip.info 的 JSON API。

                from urllib.request import urlopen
                import json
                url = 'http://api.hostip.info/get_json.php'
                info = json.loads(urlopen(url).read().decode('utf-8'))
                print(info['ip'])
                

                您当然可以添加一些错误检查、超时条件和一些便利:

                #!/usr/bin/env python3
                from urllib.request import urlopen
                from urllib.error import URLError
                import json
                
                try:
                    url = 'http://api.hostip.info/get_json.php'
                    info = json.loads(urlopen(url, timeout = 15).read().decode('utf-8'))
                    print(info['ip'])
                except URLError as e:
                    print(e.reason, end=' ') # e.g. 'timed out'
                    print('(are you connected to the internet?)')
                except KeyboardInterrupt:
                    pass
                

                【讨论】:

                  【解决方案19】:
                  In [1]: import stun
                  
                  stun.get_ip_info()
                  ('Restric NAT', 'xx.xx.xx.xx', 55320)
                  

                  【讨论】:

                  • 眩晕库从何而来?
                  【解决方案20】:

                  使用 Python 2.7.6 和 2.7.13

                  import urllib2  
                  req = urllib2.Request('http://icanhazip.com', data=None)  
                  response = urllib2.urlopen(req, timeout=5)  
                  print(response.read())
                  

                  【讨论】:

                    【解决方案21】:

                    我喜欢Sergiy Ostrovsky's answer,但我认为现在有一种更简洁的方式来做到这一点。

                    1. 安装ipify库。
                    pip install ipify
                    
                    1. 在您的 Python 程序中导入和使用该库。
                    import ipify
                    ip = ipify.get_ip()
                    

                    【讨论】:

                      【解决方案22】:
                      ipWebCode = urllib.request.urlopen("http://ip.nefsc.noaa.gov").read().decode("utf8")
                      ipWebCode=ipWebCode.split("color=red> ")
                      ipWebCode = ipWebCode[1]
                      ipWebCode = ipWebCode.split("</font>")
                      externalIp = ipWebCode[0]
                      

                      这是我为另一个程序编写的简短 sn-p。诀窍是找到一个足够简单的网站,这样剖析 html 就不那么痛苦了。

                      【讨论】:

                      • 不幸的是服务消失了:c
                      【解决方案23】:

                      这是另一个替代脚本。

                      def track_ip():
                         """
                         Returns Dict with the following keys:
                         - ip
                         - latlong
                         - country
                         - city
                         - user-agent
                         """
                      
                         conn = httplib.HTTPConnection("www.trackip.net")
                         conn.request("GET", "/ip?json")
                         resp = conn.getresponse()
                         print resp.status, resp.reason
                      
                         if resp.status == 200:
                             ip = json.loads(resp.read())
                         else:
                             print 'Connection Error: %s' % resp.reason
                      
                         conn.close()
                         return ip
                      

                      编辑:不要忘记导入 httplib 和 json

                      【讨论】:

                      • 这个答案曾经对我有用,但是在使用 conda 更新时软件包会中断,所以我放弃了这个答案以获得更简单的解决方案@Hors Sujet in stackoverflow.com/questions/24508730/…
                      【解决方案24】:

                      如果您只是为自己编写而不是为通用应用程序编写,您可以在路由器设置页面上找到地址,然后从该页面的 html 中抓取它。这对我的 SMC 路由器很有效。一次阅读和一次简单的 RE 搜索,我找到了。

                      我这样做的特别兴趣是在我不在家时让我知道我的家庭 IP 地址,这样我就可以通过 VNC 回来。多行几行 Python 将地址存储在 Dropbox 中以供外部访问,如果它看到更改,甚至会通过电子邮件发送给我。我已经安排它在启动时发生,之后每小时一次。

                      【讨论】:

                        【解决方案25】:

                        使用这个脚本:

                        import urllib, json
                        
                        data = json.loads(urllib.urlopen("http://ip.jsontest.com/").read())
                        print data["ip"]
                        

                        没有 json :

                        import urllib, re
                        
                        data = re.search('"([0-9.]*)"', urllib.urlopen("http://ip.jsontest.com/").read()).group(1)
                        print data
                        

                        【讨论】:

                          【解决方案26】:

                          导入操作系统 public_ip = os.system("inxi -i |grep 'WAN IP'") 打印(public_ip)

                          【讨论】:

                          • 请提供一些关于代码在做什么的解释,以及它与其他解决方案的不同之处。
                          • @decorator-factory 我不推荐这个解决方案,因为它假定您使用的是安装了inxi (smxi.org/docs/inxi.htm) 的系统,除非您使用的是 Linux 发行版附带它,你可能没有它。
                          【解决方案27】:

                          很遗憾,如果不咨询互联网上的计算机,就无法获取您的外部 IP 地址。充其量,您可以获得网卡的本地网络 IP 地址(可能是 192.16.. 地址)。

                          您可以使用whatismyip 模块获取外部IP 地址。它在 Python 3 标准库之外没有依赖项。它连接到公共 STUN 服务器和 what-is-my-ip 网站以查找 IPv4 或 IPv6 地址。运行pip install whatismyip

                          例子:

                          >>> import whatismyip
                          >>> whatismyip.amionline()
                          True
                          >>> whatismyip.whatismyip()  # Prefers IPv4 addresses, but can return either IPv4 or IPv6.
                          '69.89.31.226'
                          >>> whatismyip.whatismyipv4()
                          '69.89.31.226'
                          >>> whatismyip.whatismyipv6()
                          '2345:0425:2CA1:0000:0000:0567:5673:23b5'
                          

                          【讨论】:

                            【解决方案28】:

                            如果你对点击任何 url 获取公共 ip 不感兴趣,我认为以下代码可以帮助你使用机器的 python 获取公共 ip

                            import os
                            externalIP  = os.popen("ifconfig | grep 'inet' | cut -d: -f2 | awk '{print $2}' | sed -n 3p").readline()
                            print externalIP
                            

                            sed -n 3p 线路根据您用于连接设备的网络而有所不同。

                            我遇到了同样的问题,我需要访问我的服务器的 iot 设备的公共 ip。但是公共 ip 在 ifconfig 命令中完全不同,而我从请求对象进入服务器的 ip。在此之后,我在我的请求中添加了额外的参数,以将设备的 ip 发送到我的服务器。

                            希望对你有帮助

                            【讨论】:

                              【解决方案29】:
                              import os
                              externalIp = os.popen("ipconfig").read().split(":")[15][1:14]
                              

                              可能需要更改一些数字,但这对我有用

                              【讨论】:

                                猜你喜欢
                                • 2023-03-05
                                • 1970-01-01
                                • 2021-11-20
                                • 2013-04-03
                                • 2016-03-10
                                • 1970-01-01
                                • 2013-08-04
                                • 1970-01-01
                                相关资源
                                最近更新 更多